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