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