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