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