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