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