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 = "readv", .ret_type = 1, .nargs = 3, 391 .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 } } }, 392 { .name = "readlink", .ret_type = 1, .nargs = 3, 393 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } }, 394 { .name = "readlinkat", .ret_type = 1, .nargs = 4, 395 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 }, 396 { Sizet, 3 } } }, 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, "0x%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, "0x%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, "0x%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, "0x%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, "0x%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 recv, struct sctp_sndrcvinfo *info) 1312 { 1313 fprintf(fp, "{sid=%u,", info->sinfo_stream); 1314 if (recv) { 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 (!recv) { 1321 fprintf(fp, "ctx=%u,", info->sinfo_context); 1322 fprintf(fp, "ttl=%u,", info->sinfo_timetolive); 1323 } 1324 if (recv) { 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 recv, 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, recv, 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 recv, 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 cmsgbuf = calloc(1, len); 1497 if (get_struct(pid, msghdr->msg_control, cmsgbuf, len) == -1) { 1498 fprintf(fp, "0x%p", msghdr); 1499 free(cmsgbuf); 1500 } 1501 msghdr->msg_control = cmsgbuf; 1502 first = true; 1503 fputs("{", fp); 1504 for (cmsghdr = CMSG_FIRSTHDR(msghdr); 1505 cmsghdr != NULL; 1506 cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) { 1507 level = cmsghdr->cmsg_level; 1508 type = cmsghdr->cmsg_type; 1509 len = cmsghdr->cmsg_len; 1510 fprintf(fp, "%s{level=", first ? "" : ","); 1511 print_integer_arg(sysdecode_sockopt_level, fp, level); 1512 fputs(",type=", fp); 1513 temp = sysdecode_cmsg_type(level, type); 1514 if (temp) { 1515 fputs(temp, fp); 1516 } else { 1517 fprintf(fp, "%d", type); 1518 } 1519 fputs(",data=", fp); 1520 switch (level) { 1521 case IPPROTO_SCTP: 1522 print_sctp_cmsg(fp, recv, cmsghdr); 1523 break; 1524 default: 1525 print_gen_cmsg(fp, cmsghdr); 1526 break; 1527 } 1528 fputs("}", fp); 1529 } 1530 fputs("}", fp); 1531 free(cmsgbuf); 1532 } 1533 1534 /* 1535 * Converts a syscall argument into a string. Said string is 1536 * allocated via malloc(), so needs to be free()'d. sc is 1537 * a pointer to the syscall description (see above); args is 1538 * an array of all of the system call arguments. 1539 */ 1540 char * 1541 print_arg(struct syscall_args *sc, unsigned long *args, long *retval, 1542 struct trussinfo *trussinfo) 1543 { 1544 FILE *fp; 1545 char *tmp; 1546 size_t tmplen; 1547 pid_t pid; 1548 1549 fp = open_memstream(&tmp, &tmplen); 1550 pid = trussinfo->curthread->proc->pid; 1551 switch (sc->type & ARG_MASK) { 1552 case Hex: 1553 fprintf(fp, "0x%x", (int)args[sc->offset]); 1554 break; 1555 case Octal: 1556 fprintf(fp, "0%o", (int)args[sc->offset]); 1557 break; 1558 case Int: 1559 fprintf(fp, "%d", (int)args[sc->offset]); 1560 break; 1561 case UInt: 1562 fprintf(fp, "%u", (unsigned int)args[sc->offset]); 1563 break; 1564 case PUInt: { 1565 unsigned int val; 1566 1567 if (get_struct(pid, (void *)args[sc->offset], &val, 1568 sizeof(val)) == 0) 1569 fprintf(fp, "{ %u }", val); 1570 else 1571 fprintf(fp, "0x%lx", args[sc->offset]); 1572 break; 1573 } 1574 case LongHex: 1575 fprintf(fp, "0x%lx", args[sc->offset]); 1576 break; 1577 case Long: 1578 fprintf(fp, "%ld", args[sc->offset]); 1579 break; 1580 case Sizet: 1581 fprintf(fp, "%zu", (size_t)args[sc->offset]); 1582 break; 1583 case Name: { 1584 /* NULL-terminated string. */ 1585 char *tmp2; 1586 1587 tmp2 = get_string(pid, (void*)args[sc->offset], 0); 1588 fprintf(fp, "\"%s\"", tmp2); 1589 free(tmp2); 1590 break; 1591 } 1592 case BinString: { 1593 /* 1594 * Binary block of data that might have printable characters. 1595 * XXX If type|OUT, assume that the length is the syscall's 1596 * return value. Otherwise, assume that the length of the block 1597 * is in the next syscall argument. 1598 */ 1599 int max_string = trussinfo->strsize; 1600 char tmp2[max_string + 1], *tmp3; 1601 int len; 1602 int truncated = 0; 1603 1604 if (sc->type & OUT) 1605 len = retval[0]; 1606 else 1607 len = args[sc->offset + 1]; 1608 1609 /* 1610 * Don't print more than max_string characters, to avoid word 1611 * wrap. If we have to truncate put some ... after the string. 1612 */ 1613 if (len > max_string) { 1614 len = max_string; 1615 truncated = 1; 1616 } 1617 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) 1618 != -1) { 1619 tmp3 = malloc(len * 4 + 1); 1620 while (len) { 1621 if (strvisx(tmp3, tmp2, len, 1622 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 1623 break; 1624 len--; 1625 truncated = 1; 1626 } 1627 fprintf(fp, "\"%s\"%s", tmp3, truncated ? 1628 "..." : ""); 1629 free(tmp3); 1630 } else { 1631 fprintf(fp, "0x%lx", args[sc->offset]); 1632 } 1633 break; 1634 } 1635 case ExecArgs: 1636 case ExecEnv: 1637 case StringArray: { 1638 uintptr_t addr; 1639 union { 1640 char *strarray[0]; 1641 char buf[PAGE_SIZE]; 1642 } u; 1643 char *string; 1644 size_t len; 1645 u_int first, i; 1646 1647 /* 1648 * Only parse argv[] and environment arrays from exec calls 1649 * if requested. 1650 */ 1651 if (((sc->type & ARG_MASK) == ExecArgs && 1652 (trussinfo->flags & EXECVEARGS) == 0) || 1653 ((sc->type & ARG_MASK) == ExecEnv && 1654 (trussinfo->flags & EXECVEENVS) == 0)) { 1655 fprintf(fp, "0x%lx", args[sc->offset]); 1656 break; 1657 } 1658 1659 /* 1660 * Read a page of pointers at a time. Punt if the top-level 1661 * pointer is not aligned. Note that the first read is of 1662 * a partial page. 1663 */ 1664 addr = args[sc->offset]; 1665 if (addr % sizeof(char *) != 0) { 1666 fprintf(fp, "0x%lx", args[sc->offset]); 1667 break; 1668 } 1669 1670 len = PAGE_SIZE - (addr & PAGE_MASK); 1671 if (get_struct(pid, (void *)addr, u.buf, len) == -1) { 1672 fprintf(fp, "0x%lx", args[sc->offset]); 1673 break; 1674 } 1675 1676 fputc('[', fp); 1677 first = 1; 1678 i = 0; 1679 while (u.strarray[i] != NULL) { 1680 string = get_string(pid, u.strarray[i], 0); 1681 fprintf(fp, "%s \"%s\"", first ? "" : ",", string); 1682 free(string); 1683 first = 0; 1684 1685 i++; 1686 if (i == len / sizeof(char *)) { 1687 addr += len; 1688 len = PAGE_SIZE; 1689 if (get_struct(pid, (void *)addr, u.buf, len) == 1690 -1) { 1691 fprintf(fp, ", <inval>"); 1692 break; 1693 } 1694 i = 0; 1695 } 1696 } 1697 fputs(" ]", fp); 1698 break; 1699 } 1700 #ifdef __LP64__ 1701 case Quad: 1702 fprintf(fp, "%ld", args[sc->offset]); 1703 break; 1704 case QuadHex: 1705 fprintf(fp, "0x%lx", args[sc->offset]); 1706 break; 1707 #else 1708 case Quad: 1709 case QuadHex: { 1710 unsigned long long ll; 1711 1712 #if _BYTE_ORDER == _LITTLE_ENDIAN 1713 ll = (unsigned long long)args[sc->offset + 1] << 32 | 1714 args[sc->offset]; 1715 #else 1716 ll = (unsigned long long)args[sc->offset] << 32 | 1717 args[sc->offset + 1]; 1718 #endif 1719 if ((sc->type & ARG_MASK) == Quad) 1720 fprintf(fp, "%lld", ll); 1721 else 1722 fprintf(fp, "0x%llx", ll); 1723 break; 1724 } 1725 #endif 1726 case PQuadHex: { 1727 uint64_t val; 1728 1729 if (get_struct(pid, (void *)args[sc->offset], &val, 1730 sizeof(val)) == 0) 1731 fprintf(fp, "{ 0x%jx }", (uintmax_t)val); 1732 else 1733 fprintf(fp, "0x%lx", args[sc->offset]); 1734 break; 1735 } 1736 case Ptr: 1737 fprintf(fp, "0x%lx", args[sc->offset]); 1738 break; 1739 case Readlinkres: { 1740 char *tmp2; 1741 1742 if (retval[0] == -1) 1743 break; 1744 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]); 1745 fprintf(fp, "\"%s\"", tmp2); 1746 free(tmp2); 1747 break; 1748 } 1749 case Ioctl: { 1750 const char *temp; 1751 unsigned long cmd; 1752 1753 cmd = args[sc->offset]; 1754 temp = sysdecode_ioctlname(cmd); 1755 if (temp) 1756 fputs(temp, fp); 1757 else { 1758 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 1759 cmd, cmd & IOC_OUT ? "R" : "", 1760 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd), 1761 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?', 1762 cmd & 0xFF, IOCPARM_LEN(cmd)); 1763 } 1764 break; 1765 } 1766 case Timespec: { 1767 struct timespec ts; 1768 1769 if (get_struct(pid, (void *)args[sc->offset], &ts, 1770 sizeof(ts)) != -1) 1771 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec, 1772 ts.tv_nsec); 1773 else 1774 fprintf(fp, "0x%lx", args[sc->offset]); 1775 break; 1776 } 1777 case Timespec2: { 1778 struct timespec ts[2]; 1779 const char *sep; 1780 unsigned int i; 1781 1782 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) 1783 != -1) { 1784 fputs("{ ", fp); 1785 sep = ""; 1786 for (i = 0; i < nitems(ts); i++) { 1787 fputs(sep, fp); 1788 sep = ", "; 1789 switch (ts[i].tv_nsec) { 1790 case UTIME_NOW: 1791 fprintf(fp, "UTIME_NOW"); 1792 break; 1793 case UTIME_OMIT: 1794 fprintf(fp, "UTIME_OMIT"); 1795 break; 1796 default: 1797 fprintf(fp, "%jd.%09ld", 1798 (intmax_t)ts[i].tv_sec, 1799 ts[i].tv_nsec); 1800 break; 1801 } 1802 } 1803 fputs(" }", fp); 1804 } else 1805 fprintf(fp, "0x%lx", args[sc->offset]); 1806 break; 1807 } 1808 case Timeval: { 1809 struct timeval tv; 1810 1811 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1812 != -1) 1813 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec, 1814 tv.tv_usec); 1815 else 1816 fprintf(fp, "0x%lx", args[sc->offset]); 1817 break; 1818 } 1819 case Timeval2: { 1820 struct timeval tv[2]; 1821 1822 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1823 != -1) 1824 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1825 (intmax_t)tv[0].tv_sec, tv[0].tv_usec, 1826 (intmax_t)tv[1].tv_sec, tv[1].tv_usec); 1827 else 1828 fprintf(fp, "0x%lx", args[sc->offset]); 1829 break; 1830 } 1831 case Itimerval: { 1832 struct itimerval itv; 1833 1834 if (get_struct(pid, (void *)args[sc->offset], &itv, 1835 sizeof(itv)) != -1) 1836 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1837 (intmax_t)itv.it_interval.tv_sec, 1838 itv.it_interval.tv_usec, 1839 (intmax_t)itv.it_value.tv_sec, 1840 itv.it_value.tv_usec); 1841 else 1842 fprintf(fp, "0x%lx", args[sc->offset]); 1843 break; 1844 } 1845 case LinuxSockArgs: 1846 { 1847 struct linux_socketcall_args largs; 1848 1849 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs, 1850 sizeof(largs)) != -1) 1851 fprintf(fp, "{ %s, 0x%lx }", 1852 lookup(linux_socketcall_ops, largs.what, 10), 1853 (long unsigned int)largs.args); 1854 else 1855 fprintf(fp, "0x%lx", args[sc->offset]); 1856 break; 1857 } 1858 case Pollfd: { 1859 /* 1860 * XXX: A Pollfd argument expects the /next/ syscall argument 1861 * to be the number of fds in the array. This matches the poll 1862 * syscall. 1863 */ 1864 struct pollfd *pfd; 1865 int numfds = args[sc->offset + 1]; 1866 size_t bytes = sizeof(struct pollfd) * numfds; 1867 int i; 1868 1869 if ((pfd = malloc(bytes)) == NULL) 1870 err(1, "Cannot malloc %zu bytes for pollfd array", 1871 bytes); 1872 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) 1873 != -1) { 1874 fputs("{", fp); 1875 for (i = 0; i < numfds; i++) { 1876 fprintf(fp, " %d/%s", pfd[i].fd, 1877 xlookup_bits(poll_flags, pfd[i].events)); 1878 } 1879 fputs(" }", fp); 1880 } else { 1881 fprintf(fp, "0x%lx", args[sc->offset]); 1882 } 1883 free(pfd); 1884 break; 1885 } 1886 case Fd_set: { 1887 /* 1888 * XXX: A Fd_set argument expects the /first/ syscall argument 1889 * to be the number of fds in the array. This matches the 1890 * select syscall. 1891 */ 1892 fd_set *fds; 1893 int numfds = args[0]; 1894 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 1895 int i; 1896 1897 if ((fds = malloc(bytes)) == NULL) 1898 err(1, "Cannot malloc %zu bytes for fd_set array", 1899 bytes); 1900 if (get_struct(pid, (void *)args[sc->offset], fds, bytes) 1901 != -1) { 1902 fputs("{", fp); 1903 for (i = 0; i < numfds; i++) { 1904 if (FD_ISSET(i, fds)) 1905 fprintf(fp, " %d", i); 1906 } 1907 fputs(" }", fp); 1908 } else 1909 fprintf(fp, "0x%lx", args[sc->offset]); 1910 free(fds); 1911 break; 1912 } 1913 case Signal: 1914 fputs(strsig2(args[sc->offset]), fp); 1915 break; 1916 case Sigset: { 1917 long sig; 1918 sigset_t ss; 1919 int i, first; 1920 1921 sig = args[sc->offset]; 1922 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 1923 sizeof(ss)) == -1) { 1924 fprintf(fp, "0x%lx", args[sc->offset]); 1925 break; 1926 } 1927 fputs("{ ", fp); 1928 first = 1; 1929 for (i = 1; i < sys_nsig; i++) { 1930 if (sigismember(&ss, i)) { 1931 fprintf(fp, "%s%s", !first ? "|" : "", 1932 strsig2(i)); 1933 first = 0; 1934 } 1935 } 1936 if (!first) 1937 fputc(' ', fp); 1938 fputc('}', fp); 1939 break; 1940 } 1941 case Sigprocmask: 1942 print_integer_arg(sysdecode_sigprocmask_how, fp, 1943 args[sc->offset]); 1944 break; 1945 case Fcntlflag: 1946 /* XXX: Output depends on the value of the previous argument. */ 1947 if (sysdecode_fcntl_arg_p(args[sc->offset - 1])) 1948 sysdecode_fcntl_arg(fp, args[sc->offset - 1], 1949 args[sc->offset], 16); 1950 break; 1951 case Open: 1952 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]); 1953 break; 1954 case Fcntl: 1955 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]); 1956 break; 1957 case Mprot: 1958 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]); 1959 break; 1960 case Mmapflags: 1961 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]); 1962 break; 1963 case Whence: 1964 print_integer_arg(sysdecode_whence, fp, args[sc->offset]); 1965 break; 1966 case Sockdomain: 1967 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]); 1968 break; 1969 case Socktype: 1970 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]); 1971 break; 1972 case Shutdown: 1973 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]); 1974 break; 1975 case Resource: 1976 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]); 1977 break; 1978 case RusageWho: 1979 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]); 1980 break; 1981 case Pathconf: 1982 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]); 1983 break; 1984 case Rforkflags: 1985 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]); 1986 break; 1987 case Sockaddr: { 1988 socklen_t len; 1989 1990 if (args[sc->offset] == 0) { 1991 fputs("NULL", fp); 1992 break; 1993 } 1994 1995 /* 1996 * Extract the address length from the next argument. If 1997 * this is an output sockaddr (OUT is set), then the 1998 * next argument is a pointer to a socklen_t. Otherwise 1999 * the next argument contains a socklen_t by value. 2000 */ 2001 if (sc->type & OUT) { 2002 if (get_struct(pid, (void *)args[sc->offset + 1], 2003 &len, sizeof(len)) == -1) { 2004 fprintf(fp, "0x%lx", args[sc->offset]); 2005 break; 2006 } 2007 } else 2008 len = args[sc->offset + 1]; 2009 2010 print_sockaddr(fp, trussinfo, (void *)args[sc->offset], len); 2011 break; 2012 } 2013 case Sigaction: { 2014 struct sigaction sa; 2015 2016 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) 2017 != -1) { 2018 fputs("{ ", fp); 2019 if (sa.sa_handler == SIG_DFL) 2020 fputs("SIG_DFL", fp); 2021 else if (sa.sa_handler == SIG_IGN) 2022 fputs("SIG_IGN", fp); 2023 else 2024 fprintf(fp, "%p", sa.sa_handler); 2025 fprintf(fp, " %s ss_t }", 2026 xlookup_bits(sigaction_flags, sa.sa_flags)); 2027 } else 2028 fprintf(fp, "0x%lx", args[sc->offset]); 2029 break; 2030 } 2031 case Kevent: { 2032 /* 2033 * XXX XXX: The size of the array is determined by either the 2034 * next syscall argument, or by the syscall return value, 2035 * depending on which argument number we are. This matches the 2036 * kevent syscall, but luckily that's the only syscall that uses 2037 * them. 2038 */ 2039 struct kevent *ke; 2040 int numevents = -1; 2041 size_t bytes; 2042 int i; 2043 2044 if (sc->offset == 1) 2045 numevents = args[sc->offset+1]; 2046 else if (sc->offset == 3 && retval[0] != -1) 2047 numevents = retval[0]; 2048 2049 if (numevents >= 0) { 2050 bytes = sizeof(struct kevent) * numevents; 2051 if ((ke = malloc(bytes)) == NULL) 2052 err(1, 2053 "Cannot malloc %zu bytes for kevent array", 2054 bytes); 2055 } else 2056 ke = NULL; 2057 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 2058 ke, bytes) != -1) { 2059 fputc('{', fp); 2060 for (i = 0; i < numevents; i++) { 2061 fputc(' ', fp); 2062 print_kevent(fp, &ke[i]); 2063 } 2064 fputs(" }", fp); 2065 } else { 2066 fprintf(fp, "0x%lx", args[sc->offset]); 2067 } 2068 free(ke); 2069 break; 2070 } 2071 case Kevent11: { 2072 struct kevent_freebsd11 *ke11; 2073 struct kevent ke; 2074 int numevents = -1; 2075 size_t bytes; 2076 int i; 2077 2078 if (sc->offset == 1) 2079 numevents = args[sc->offset+1]; 2080 else if (sc->offset == 3 && retval[0] != -1) 2081 numevents = retval[0]; 2082 2083 if (numevents >= 0) { 2084 bytes = sizeof(struct kevent_freebsd11) * numevents; 2085 if ((ke11 = malloc(bytes)) == NULL) 2086 err(1, 2087 "Cannot malloc %zu bytes for kevent array", 2088 bytes); 2089 } else 2090 ke11 = NULL; 2091 memset(&ke, 0, sizeof(ke)); 2092 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 2093 ke11, bytes) != -1) { 2094 fputc('{', fp); 2095 for (i = 0; i < numevents; i++) { 2096 fputc(' ', fp); 2097 ke.ident = ke11[i].ident; 2098 ke.filter = ke11[i].filter; 2099 ke.flags = ke11[i].flags; 2100 ke.fflags = ke11[i].fflags; 2101 ke.data = ke11[i].data; 2102 ke.udata = ke11[i].udata; 2103 print_kevent(fp, &ke); 2104 } 2105 fputs(" }", fp); 2106 } else { 2107 fprintf(fp, "0x%lx", args[sc->offset]); 2108 } 2109 free(ke11); 2110 break; 2111 } 2112 case Stat: { 2113 struct stat st; 2114 2115 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 2116 != -1) { 2117 char mode[12]; 2118 2119 strmode(st.st_mode, mode); 2120 fprintf(fp, 2121 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 2122 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 2123 (long)st.st_blksize); 2124 } else { 2125 fprintf(fp, "0x%lx", args[sc->offset]); 2126 } 2127 break; 2128 } 2129 case Stat11: { 2130 struct freebsd11_stat st; 2131 2132 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 2133 != -1) { 2134 char mode[12]; 2135 2136 strmode(st.st_mode, mode); 2137 fprintf(fp, 2138 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 2139 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 2140 (long)st.st_blksize); 2141 } else { 2142 fprintf(fp, "0x%lx", args[sc->offset]); 2143 } 2144 break; 2145 } 2146 case StatFs: { 2147 unsigned int i; 2148 struct statfs buf; 2149 2150 if (get_struct(pid, (void *)args[sc->offset], &buf, 2151 sizeof(buf)) != -1) { 2152 char fsid[17]; 2153 2154 bzero(fsid, sizeof(fsid)); 2155 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) { 2156 for (i = 0; i < sizeof(buf.f_fsid); i++) 2157 snprintf(&fsid[i*2], 2158 sizeof(fsid) - (i*2), "%02x", 2159 ((u_char *)&buf.f_fsid)[i]); 2160 } 2161 fprintf(fp, 2162 "{ fstypename=%s,mntonname=%s,mntfromname=%s," 2163 "fsid=%s }", buf.f_fstypename, buf.f_mntonname, 2164 buf.f_mntfromname, fsid); 2165 } else 2166 fprintf(fp, "0x%lx", args[sc->offset]); 2167 break; 2168 } 2169 2170 case Rusage: { 2171 struct rusage ru; 2172 2173 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) 2174 != -1) { 2175 fprintf(fp, 2176 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }", 2177 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 2178 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 2179 ru.ru_inblock, ru.ru_oublock); 2180 } else 2181 fprintf(fp, "0x%lx", args[sc->offset]); 2182 break; 2183 } 2184 case Rlimit: { 2185 struct rlimit rl; 2186 2187 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) 2188 != -1) { 2189 fprintf(fp, "{ cur=%ju,max=%ju }", 2190 rl.rlim_cur, rl.rlim_max); 2191 } else 2192 fprintf(fp, "0x%lx", args[sc->offset]); 2193 break; 2194 } 2195 case ExitStatus: { 2196 int status; 2197 2198 if (get_struct(pid, (void *)args[sc->offset], &status, 2199 sizeof(status)) != -1) { 2200 fputs("{ ", fp); 2201 if (WIFCONTINUED(status)) 2202 fputs("CONTINUED", fp); 2203 else if (WIFEXITED(status)) 2204 fprintf(fp, "EXITED,val=%d", 2205 WEXITSTATUS(status)); 2206 else if (WIFSIGNALED(status)) 2207 fprintf(fp, "SIGNALED,sig=%s%s", 2208 strsig2(WTERMSIG(status)), 2209 WCOREDUMP(status) ? ",cored" : ""); 2210 else 2211 fprintf(fp, "STOPPED,sig=%s", 2212 strsig2(WTERMSIG(status))); 2213 fputs(" }", fp); 2214 } else 2215 fprintf(fp, "0x%lx", args[sc->offset]); 2216 break; 2217 } 2218 case Waitoptions: 2219 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]); 2220 break; 2221 case Idtype: 2222 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]); 2223 break; 2224 case Procctl: 2225 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]); 2226 break; 2227 case Umtxop: 2228 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]); 2229 break; 2230 case Atfd: 2231 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]); 2232 break; 2233 case Atflags: 2234 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]); 2235 break; 2236 case Accessmode: 2237 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]); 2238 break; 2239 case Sysarch: 2240 print_integer_arg(sysdecode_sysarch_number, fp, 2241 args[sc->offset]); 2242 break; 2243 case PipeFds: 2244 /* 2245 * The pipe() system call in the kernel returns its 2246 * two file descriptors via return values. However, 2247 * the interface exposed by libc is that pipe() 2248 * accepts a pointer to an array of descriptors. 2249 * Format the output to match the libc API by printing 2250 * the returned file descriptors as a fake argument. 2251 * 2252 * Overwrite the first retval to signal a successful 2253 * return as well. 2254 */ 2255 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]); 2256 retval[0] = 0; 2257 break; 2258 case Utrace: { 2259 size_t len; 2260 void *utrace_addr; 2261 2262 len = args[sc->offset + 1]; 2263 utrace_addr = calloc(1, len); 2264 if (get_struct(pid, (void *)args[sc->offset], 2265 (void *)utrace_addr, len) != -1) 2266 print_utrace(fp, utrace_addr, len); 2267 else 2268 fprintf(fp, "0x%lx", args[sc->offset]); 2269 free(utrace_addr); 2270 break; 2271 } 2272 case IntArray: { 2273 int descriptors[16]; 2274 unsigned long i, ndescriptors; 2275 bool truncated; 2276 2277 ndescriptors = args[sc->offset + 1]; 2278 truncated = false; 2279 if (ndescriptors > nitems(descriptors)) { 2280 ndescriptors = nitems(descriptors); 2281 truncated = true; 2282 } 2283 if (get_struct(pid, (void *)args[sc->offset], 2284 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) { 2285 fprintf(fp, "{"); 2286 for (i = 0; i < ndescriptors; i++) 2287 fprintf(fp, i == 0 ? " %d" : ", %d", 2288 descriptors[i]); 2289 fprintf(fp, truncated ? ", ... }" : " }"); 2290 } else 2291 fprintf(fp, "0x%lx", args[sc->offset]); 2292 break; 2293 } 2294 case Pipe2: 2295 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]); 2296 break; 2297 case CapFcntlRights: { 2298 uint32_t rights; 2299 2300 if (sc->type & OUT) { 2301 if (get_struct(pid, (void *)args[sc->offset], &rights, 2302 sizeof(rights)) == -1) { 2303 fprintf(fp, "0x%lx", args[sc->offset]); 2304 break; 2305 } 2306 } else 2307 rights = args[sc->offset]; 2308 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights); 2309 break; 2310 } 2311 case Fadvice: 2312 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]); 2313 break; 2314 case FileFlags: { 2315 fflags_t rem; 2316 2317 if (!sysdecode_fileflags(fp, args[sc->offset], &rem)) 2318 fprintf(fp, "0x%x", rem); 2319 else if (rem != 0) 2320 fprintf(fp, "|0x%x", rem); 2321 break; 2322 } 2323 case Flockop: 2324 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]); 2325 break; 2326 case Getfsstatmode: 2327 print_integer_arg(sysdecode_getfsstat_mode, fp, 2328 args[sc->offset]); 2329 break; 2330 case Kldsymcmd: 2331 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]); 2332 break; 2333 case Kldunloadflags: 2334 print_integer_arg(sysdecode_kldunload_flags, fp, 2335 args[sc->offset]); 2336 break; 2337 case Madvice: 2338 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]); 2339 break; 2340 case Socklent: 2341 fprintf(fp, "%u", (socklen_t)args[sc->offset]); 2342 break; 2343 case Sockprotocol: { 2344 const char *temp; 2345 int domain, protocol; 2346 2347 domain = args[sc->offset - 2]; 2348 protocol = args[sc->offset]; 2349 if (protocol == 0) { 2350 fputs("0", fp); 2351 } else { 2352 temp = sysdecode_socket_protocol(domain, protocol); 2353 if (temp) { 2354 fputs(temp, fp); 2355 } else { 2356 fprintf(fp, "%d", protocol); 2357 } 2358 } 2359 break; 2360 } 2361 case Sockoptlevel: 2362 print_integer_arg(sysdecode_sockopt_level, fp, 2363 args[sc->offset]); 2364 break; 2365 case Sockoptname: { 2366 const char *temp; 2367 int level, name; 2368 2369 level = args[sc->offset - 1]; 2370 name = args[sc->offset]; 2371 temp = sysdecode_sockopt_name(level, name); 2372 if (temp) { 2373 fputs(temp, fp); 2374 } else { 2375 fprintf(fp, "%d", name); 2376 } 2377 break; 2378 } 2379 case Msgflags: 2380 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]); 2381 break; 2382 case CapRights: { 2383 cap_rights_t rights; 2384 2385 if (get_struct(pid, (void *)args[sc->offset], &rights, 2386 sizeof(rights)) != -1) { 2387 fputs("{ ", fp); 2388 sysdecode_cap_rights(fp, &rights); 2389 fputs(" }", fp); 2390 } else 2391 fprintf(fp, "0x%lx", args[sc->offset]); 2392 break; 2393 } 2394 case Acltype: 2395 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]); 2396 break; 2397 case Extattrnamespace: 2398 print_integer_arg(sysdecode_extattrnamespace, fp, 2399 args[sc->offset]); 2400 break; 2401 case Minherit: 2402 print_integer_arg(sysdecode_minherit_inherit, fp, 2403 args[sc->offset]); 2404 break; 2405 case Mlockall: 2406 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]); 2407 break; 2408 case Mountflags: 2409 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]); 2410 break; 2411 case Msync: 2412 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]); 2413 break; 2414 case Priowhich: 2415 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]); 2416 break; 2417 case Ptraceop: 2418 print_integer_arg(sysdecode_ptrace_request, fp, 2419 args[sc->offset]); 2420 break; 2421 case Quotactlcmd: 2422 if (!sysdecode_quotactl_cmd(fp, args[sc->offset])) 2423 fprintf(fp, "%#x", (int)args[sc->offset]); 2424 break; 2425 case Reboothowto: 2426 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]); 2427 break; 2428 case Rtpriofunc: 2429 print_integer_arg(sysdecode_rtprio_function, fp, 2430 args[sc->offset]); 2431 break; 2432 case Schedpolicy: 2433 print_integer_arg(sysdecode_scheduler_policy, fp, 2434 args[sc->offset]); 2435 break; 2436 case Schedparam: { 2437 struct sched_param sp; 2438 2439 if (get_struct(pid, (void *)args[sc->offset], &sp, 2440 sizeof(sp)) != -1) 2441 fprintf(fp, "{ %d }", sp.sched_priority); 2442 else 2443 fprintf(fp, "0x%lx", args[sc->offset]); 2444 break; 2445 } 2446 case PSig: { 2447 int sig; 2448 2449 if (get_struct(pid, (void *)args[sc->offset], &sig, 2450 sizeof(sig)) == 0) 2451 fprintf(fp, "{ %s }", strsig2(sig)); 2452 else 2453 fprintf(fp, "0x%lx", args[sc->offset]); 2454 break; 2455 } 2456 case Siginfo: { 2457 siginfo_t si; 2458 2459 if (get_struct(pid, (void *)args[sc->offset], &si, 2460 sizeof(si)) != -1) { 2461 fprintf(fp, "{ signo=%s", strsig2(si.si_signo)); 2462 decode_siginfo(fp, &si); 2463 fprintf(fp, " }"); 2464 } else 2465 fprintf(fp, "0x%lx", args[sc->offset]); 2466 break; 2467 } 2468 case Iovec: 2469 /* 2470 * Print argument as an array of struct iovec, where the next 2471 * syscall argument is the number of elements of the array. 2472 */ 2473 2474 print_iovec(fp, trussinfo, (void *)args[sc->offset], 2475 (int)args[sc->offset + 1]); 2476 break; 2477 case Sctpsndrcvinfo: { 2478 struct sctp_sndrcvinfo info; 2479 2480 if (get_struct(pid, (void *)args[sc->offset], 2481 &info, sizeof(struct sctp_sndrcvinfo)) == -1) { 2482 fprintf(fp, "0x%lx", args[sc->offset]); 2483 break; 2484 } 2485 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info); 2486 break; 2487 } 2488 case Msghdr: { 2489 struct msghdr msghdr; 2490 2491 if (get_struct(pid, (void *)args[sc->offset], 2492 &msghdr, sizeof(struct msghdr)) == -1) { 2493 fprintf(fp, "0x%lx", args[sc->offset]); 2494 break; 2495 } 2496 fputs("{", fp); 2497 print_sockaddr(fp, trussinfo, msghdr.msg_name, msghdr.msg_namelen); 2498 fprintf(fp, ",%d,", msghdr.msg_namelen); 2499 print_iovec(fp, trussinfo, msghdr.msg_iov, msghdr.msg_iovlen); 2500 fprintf(fp, ",%d,", msghdr.msg_iovlen); 2501 print_cmsgs(fp, pid, sc->type & OUT, &msghdr); 2502 fprintf(fp, ",%u,", msghdr.msg_controllen); 2503 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags); 2504 fputs("}", fp); 2505 break; 2506 } 2507 2508 case CloudABIAdvice: 2509 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp); 2510 break; 2511 case CloudABIClockID: 2512 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp); 2513 break; 2514 case ClouduABIFDSFlags: 2515 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp); 2516 break; 2517 case CloudABIFDStat: { 2518 cloudabi_fdstat_t fds; 2519 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds)) 2520 != -1) { 2521 fprintf(fp, "{ %s, ", 2522 xlookup(cloudabi_filetype, fds.fs_filetype)); 2523 fprintf(fp, "%s, ... }", 2524 xlookup_bits(cloudabi_fdflags, fds.fs_flags)); 2525 } else 2526 fprintf(fp, "0x%lx", args[sc->offset]); 2527 break; 2528 } 2529 case CloudABIFileStat: { 2530 cloudabi_filestat_t fsb; 2531 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb)) 2532 != -1) 2533 fprintf(fp, "{ %s, %ju }", 2534 xlookup(cloudabi_filetype, fsb.st_filetype), 2535 (uintmax_t)fsb.st_size); 2536 else 2537 fprintf(fp, "0x%lx", args[sc->offset]); 2538 break; 2539 } 2540 case CloudABIFileType: 2541 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp); 2542 break; 2543 case CloudABIFSFlags: 2544 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp); 2545 break; 2546 case CloudABILookup: 2547 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0) 2548 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW", 2549 (int)args[sc->offset]); 2550 else 2551 fprintf(fp, "%d", (int)args[sc->offset]); 2552 break; 2553 case CloudABIMFlags: 2554 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp); 2555 break; 2556 case CloudABIMProt: 2557 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp); 2558 break; 2559 case CloudABIMSFlags: 2560 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp); 2561 break; 2562 case CloudABIOFlags: 2563 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp); 2564 break; 2565 case CloudABISDFlags: 2566 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp); 2567 break; 2568 case CloudABISignal: 2569 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp); 2570 break; 2571 case CloudABITimestamp: 2572 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000, 2573 args[sc->offset] % 1000000000); 2574 break; 2575 case CloudABIULFlags: 2576 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp); 2577 break; 2578 case CloudABIWhence: 2579 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp); 2580 break; 2581 2582 default: 2583 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 2584 } 2585 fclose(fp); 2586 return (tmp); 2587 } 2588 2589 /* 2590 * Print (to outfile) the system call and its arguments. 2591 */ 2592 void 2593 print_syscall(struct trussinfo *trussinfo) 2594 { 2595 struct threadinfo *t; 2596 const char *name; 2597 char **s_args; 2598 int i, len, nargs; 2599 2600 t = trussinfo->curthread; 2601 2602 name = t->cs.sc->name; 2603 nargs = t->cs.nargs; 2604 s_args = t->cs.s_args; 2605 2606 len = print_line_prefix(trussinfo); 2607 len += fprintf(trussinfo->outfile, "%s(", name); 2608 2609 for (i = 0; i < nargs; i++) { 2610 if (s_args[i] != NULL) 2611 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 2612 else 2613 len += fprintf(trussinfo->outfile, 2614 "<missing argument>"); 2615 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 2616 "," : ""); 2617 } 2618 len += fprintf(trussinfo->outfile, ")"); 2619 for (i = 0; i < 6 - (len / 8); i++) 2620 fprintf(trussinfo->outfile, "\t"); 2621 } 2622 2623 void 2624 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval) 2625 { 2626 struct timespec timediff; 2627 struct threadinfo *t; 2628 struct syscall *sc; 2629 int error; 2630 2631 t = trussinfo->curthread; 2632 sc = t->cs.sc; 2633 if (trussinfo->flags & COUNTONLY) { 2634 timespecsubt(&t->after, &t->before, &timediff); 2635 timespecadd(&sc->time, &timediff, &sc->time); 2636 sc->ncalls++; 2637 if (errorp) 2638 sc->nerror++; 2639 return; 2640 } 2641 2642 print_syscall(trussinfo); 2643 fflush(trussinfo->outfile); 2644 2645 if (retval == NULL) { 2646 /* 2647 * This system call resulted in the current thread's exit, 2648 * so there is no return value or error to display. 2649 */ 2650 fprintf(trussinfo->outfile, "\n"); 2651 return; 2652 } 2653 2654 if (errorp) { 2655 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi, 2656 retval[0]); 2657 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0], 2658 error == INT_MAX ? "Unknown error" : strerror(error)); 2659 } 2660 #ifndef __LP64__ 2661 else if (sc->ret_type == 2) { 2662 off_t off; 2663 2664 #if _BYTE_ORDER == _LITTLE_ENDIAN 2665 off = (off_t)retval[1] << 32 | retval[0]; 2666 #else 2667 off = (off_t)retval[0] << 32 | retval[1]; 2668 #endif 2669 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off, 2670 (intmax_t)off); 2671 } 2672 #endif 2673 else 2674 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0], 2675 retval[0]); 2676 } 2677 2678 void 2679 print_summary(struct trussinfo *trussinfo) 2680 { 2681 struct timespec total = {0, 0}; 2682 struct syscall *sc; 2683 int ncall, nerror; 2684 2685 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 2686 "syscall", "seconds", "calls", "errors"); 2687 ncall = nerror = 0; 2688 STAILQ_FOREACH(sc, &syscalls, entries) 2689 if (sc->ncalls) { 2690 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2691 sc->name, (intmax_t)sc->time.tv_sec, 2692 sc->time.tv_nsec, sc->ncalls, sc->nerror); 2693 timespecadd(&total, &sc->time, &total); 2694 ncall += sc->ncalls; 2695 nerror += sc->nerror; 2696 } 2697 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 2698 "", "-------------", "-------", "-------"); 2699 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 2700 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 2701 } 2702