syscalls.c revision 294033
1/* 2 * Copyright 1997 Sean Eric Fagan 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Sean Eric Fagan 15 * 4. Neither the name of the author may be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/10/usr.bin/truss/syscalls.c 294033 2016-01-14 19:47:52Z jhb $"); 34 35/* 36 * This file has routines used to print out system calls and their 37 * arguments. 38 */ 39 40#include <sys/types.h> 41#include <sys/event.h> 42#include <sys/ioccom.h> 43#include <sys/mman.h> 44#include <sys/mount.h> 45#include <sys/procctl.h> 46#include <sys/ptrace.h> 47#include <sys/resource.h> 48#include <sys/socket.h> 49#include <sys/stat.h> 50#include <machine/atomic.h> 51#include <errno.h> 52#include <sys/umtx.h> 53#include <sys/un.h> 54#include <sys/wait.h> 55#include <machine/sysarch.h> 56#include <netinet/in.h> 57#include <arpa/inet.h> 58 59#include <ctype.h> 60#include <err.h> 61#include <fcntl.h> 62#include <poll.h> 63#include <signal.h> 64#include <stddef.h> 65#include <stdint.h> 66#include <stdio.h> 67#include <stdlib.h> 68#include <string.h> 69#include <time.h> 70#include <unistd.h> 71#include <vis.h> 72 73#include "truss.h" 74#include "extern.h" 75#include "syscall.h" 76 77/* 64-bit alignment on 32-bit platforms. */ 78#if !defined(__LP64__) && defined(__powerpc__) 79#define QUAD_ALIGN 1 80#else 81#define QUAD_ALIGN 0 82#endif 83 84/* Number of slots needed for a 64-bit argument. */ 85#ifdef __LP64__ 86#define QUAD_SLOTS 1 87#else 88#define QUAD_SLOTS 2 89#endif 90 91/* 92 * This should probably be in its own file, sorted alphabetically. 93 */ 94static struct syscall decoded_syscalls[] = { 95 /* Native ABI */ 96 { .name = "__getcwd", .ret_type = 1, .nargs = 2, 97 .args = { { Name | OUT, 0 }, { Int, 1 } } }, 98 { .name = "_umtx_lock", .ret_type = 1, .nargs = 1, 99 .args = { { Umtx, 0 } } }, 100 { .name = "_umtx_op", .ret_type = 1, .nargs = 5, 101 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 }, 102 { Ptr, 4 } } }, 103 { .name = "_umtx_unlock", .ret_type = 1, .nargs = 1, 104 .args = { { Umtx, 0 } } }, 105 { .name = "accept", .ret_type = 1, .nargs = 3, 106 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 107 { .name = "access", .ret_type = 1, .nargs = 2, 108 .args = { { Name | IN, 0 }, { Accessmode, 1 } } }, 109 { .name = "bind", .ret_type = 1, .nargs = 3, 110 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 111 { .name = "bindat", .ret_type = 1, .nargs = 4, 112 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, 113 { Int, 3 } } }, 114 { .name = "break", .ret_type = 1, .nargs = 1, 115 .args = { { Ptr, 0 } } }, 116 { .name = "chdir", .ret_type = 1, .nargs = 1, 117 .args = { { Name, 0 } } }, 118 { .name = "chflags", .ret_type = 1, .nargs = 2, 119 .args = { { Name | IN, 0 }, { Hex, 1 } } }, 120 { .name = "chmod", .ret_type = 1, .nargs = 2, 121 .args = { { Name, 0 }, { Octal, 1 } } }, 122 { .name = "chown", .ret_type = 1, .nargs = 3, 123 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 124 { .name = "chroot", .ret_type = 1, .nargs = 1, 125 .args = { { Name, 0 } } }, 126 { .name = "clock_gettime", .ret_type = 1, .nargs = 2, 127 .args = { { Int, 0 }, { Timespec | OUT, 1 } } }, 128 { .name = "close", .ret_type = 1, .nargs = 1, 129 .args = { { Int, 0 } } }, 130 { .name = "connect", .ret_type = 1, .nargs = 3, 131 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 132 { .name = "connectat", .ret_type = 1, .nargs = 4, 133 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, 134 { Int, 3 } } }, 135 { .name = "eaccess", .ret_type = 1, .nargs = 2, 136 .args = { { Name | IN, 0 }, { Accessmode, 1 } } }, 137 { .name = "execve", .ret_type = 1, .nargs = 3, 138 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 }, 139 { ExecEnv | IN, 2 } } }, 140 { .name = "exit", .ret_type = 0, .nargs = 1, 141 .args = { { Hex, 0 } } }, 142 { .name = "faccessat", .ret_type = 1, .nargs = 4, 143 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 }, 144 { Atflags, 3 } } }, 145 { .name = "fchmod", .ret_type = 1, .nargs = 2, 146 .args = { { Int, 0 }, { Octal, 1 } } }, 147 { .name = "fchmodat", .ret_type = 1, .nargs = 4, 148 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } }, 149 { .name = "fchown", .ret_type = 1, .nargs = 3, 150 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } }, 151 { .name = "fchownat", .ret_type = 1, .nargs = 5, 152 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 }, 153 { Atflags, 4 } } }, 154 { .name = "fcntl", .ret_type = 1, .nargs = 3, 155 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } }, 156 { .name = "fstat", .ret_type = 1, .nargs = 2, 157 .args = { { Int, 0 }, { Stat | OUT, 1 } } }, 158 { .name = "fstatat", .ret_type = 1, .nargs = 4, 159 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 }, 160 { Atflags, 3 } } }, 161 { .name = "fstatfs", .ret_type = 1, .nargs = 2, 162 .args = { { Int, 0 }, { StatFs | OUT, 1 } } }, 163 { .name = "ftruncate", .ret_type = 1, .nargs = 2, 164 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } }, 165 { .name = "futimens", .ret_type = 1, .nargs = 2, 166 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } }, 167 { .name = "futimes", .ret_type = 1, .nargs = 2, 168 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } }, 169 { .name = "futimesat", .ret_type = 1, .nargs = 3, 170 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } }, 171 { .name = "getitimer", .ret_type = 1, .nargs = 2, 172 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } }, 173 { .name = "getpeername", .ret_type = 1, .nargs = 3, 174 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 175 { .name = "getpgid", .ret_type = 1, .nargs = 1, 176 .args = { { Int, 0 } } }, 177 { .name = "getrlimit", .ret_type = 1, .nargs = 2, 178 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } }, 179 { .name = "getrusage", .ret_type = 1, .nargs = 2, 180 .args = { { Int, 0 }, { Rusage | OUT, 1 } } }, 181 { .name = "getsid", .ret_type = 1, .nargs = 1, 182 .args = { { Int, 0 } } }, 183 { .name = "getsockname", .ret_type = 1, .nargs = 3, 184 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 185 { .name = "gettimeofday", .ret_type = 1, .nargs = 2, 186 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } }, 187 { .name = "ioctl", .ret_type = 1, .nargs = 3, 188 .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } }, 189 { .name = "kevent", .ret_type = 1, .nargs = 6, 190 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, 191 { Int, 4 }, { Timespec, 5 } } }, 192 { .name = "kill", .ret_type = 1, .nargs = 2, 193 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } }, 194 { .name = "kldfind", .ret_type = 1, .nargs = 1, 195 .args = { { Name | IN, 0 } } }, 196 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1, 197 .args = { { Int, 0 } } }, 198 { .name = "kldload", .ret_type = 1, .nargs = 1, 199 .args = { { Name | IN, 0 } } }, 200 { .name = "kldnext", .ret_type = 1, .nargs = 1, 201 .args = { { Int, 0 } } }, 202 { .name = "kldstat", .ret_type = 1, .nargs = 2, 203 .args = { { Int, 0 }, { Ptr, 1 } } }, 204 { .name = "kldunload", .ret_type = 1, .nargs = 1, 205 .args = { { Int, 0 } } }, 206 { .name = "kse_release", .ret_type = 0, .nargs = 1, 207 .args = { { Timespec, 0 } } }, 208 { .name = "lchflags", .ret_type = 1, .nargs = 2, 209 .args = { { Name | IN, 0 }, { Hex, 1 } } }, 210 { .name = "lchmod", .ret_type = 1, .nargs = 2, 211 .args = { { Name, 0 }, { Octal, 1 } } }, 212 { .name = "lchown", .ret_type = 1, .nargs = 3, 213 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 214 { .name = "link", .ret_type = 1, .nargs = 2, 215 .args = { { Name, 0 }, { Name, 1 } } }, 216 { .name = "linkat", .ret_type = 1, .nargs = 5, 217 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 }, 218 { Atflags, 4 } } }, 219 { .name = "lseek", .ret_type = 2, .nargs = 3, 220 .args = { { Int, 0 }, { QuadHex, 1 + QUAD_ALIGN }, 221 { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } }, 222 { .name = "lstat", .ret_type = 1, .nargs = 2, 223 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 224 { .name = "lutimes", .ret_type = 1, .nargs = 2, 225 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 226 { .name = "mkdir", .ret_type = 1, .nargs = 2, 227 .args = { { Name, 0 }, { Octal, 1 } } }, 228 { .name = "mkdirat", .ret_type = 1, .nargs = 3, 229 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } }, 230 { .name = "mkfifo", .ret_type = 1, .nargs = 2, 231 .args = { { Name, 0 }, { Octal, 1 } } }, 232 { .name = "mkfifoat", .ret_type = 1, .nargs = 3, 233 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } }, 234 { .name = "mknod", .ret_type = 1, .nargs = 3, 235 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } }, 236 { .name = "mknodat", .ret_type = 1, .nargs = 4, 237 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } }, 238 { .name = "mmap", .ret_type = 1, .nargs = 6, 239 .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, 240 { Int, 4 }, { QuadHex, 5 + QUAD_ALIGN } } }, 241 { .name = "modfind", .ret_type = 1, .nargs = 1, 242 .args = { { Name | IN, 0 } } }, 243 { .name = "mount", .ret_type = 1, .nargs = 4, 244 .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } }, 245 { .name = "mprotect", .ret_type = 1, .nargs = 3, 246 .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } }, 247 { .name = "munmap", .ret_type = 1, .nargs = 2, 248 .args = { { Ptr, 0 }, { Int, 1 } } }, 249 { .name = "nanosleep", .ret_type = 1, .nargs = 1, 250 .args = { { Timespec, 0 } } }, 251 { .name = "open", .ret_type = 1, .nargs = 3, 252 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } }, 253 { .name = "openat", .ret_type = 1, .nargs = 4, 254 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 }, 255 { Octal, 3 } } }, 256 { .name = "pathconf", .ret_type = 1, .nargs = 2, 257 .args = { { Name | IN, 0 }, { Pathconf, 1 } } }, 258 { .name = "pipe", .ret_type = 1, .nargs = 1, 259 .args = { { PipeFds | OUT, 0 } } }, 260 { .name = "pipe2", .ret_type = 1, .nargs = 2, 261 .args = { { Ptr, 0 }, { Open, 1 } } }, 262 { .name = "poll", .ret_type = 1, .nargs = 3, 263 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, 264 { .name = "posix_openpt", .ret_type = 1, .nargs = 1, 265 .args = { { Open, 0 } } }, 266 { .name = "procctl", .ret_type = 1, .nargs = 4, 267 .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN }, 268 { Procctl, 1 + QUAD_ALIGN + QUAD_SLOTS }, 269 { Ptr, 2 + QUAD_ALIGN + QUAD_SLOTS } } }, 270 { .name = "read", .ret_type = 1, .nargs = 3, 271 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } }, 272 { .name = "readlink", .ret_type = 1, .nargs = 3, 273 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Int, 2 } } }, 274 { .name = "readlinkat", .ret_type = 1, .nargs = 4, 275 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 }, 276 { Int, 3 } } }, 277 { .name = "recvfrom", .ret_type = 1, .nargs = 6, 278 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, 279 { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, 280 { .name = "rename", .ret_type = 1, .nargs = 2, 281 .args = { { Name, 0 }, { Name, 1 } } }, 282 { .name = "renameat", .ret_type = 1, .nargs = 4, 283 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } }, 284 { .name = "rfork", .ret_type = 1, .nargs = 1, 285 .args = { { Rforkflags, 0 } } }, 286 { .name = "select", .ret_type = 1, .nargs = 5, 287 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, 288 { Timeval, 4 } } }, 289 { .name = "sendto", .ret_type = 1, .nargs = 6, 290 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, 291 { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, 292 { .name = "setitimer", .ret_type = 1, .nargs = 3, 293 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } }, 294 { .name = "setrlimit", .ret_type = 1, .nargs = 2, 295 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } }, 296 { .name = "shutdown", .ret_type = 1, .nargs = 2, 297 .args = { { Int, 0 }, { Shutdown, 1 } } }, 298 { .name = "sigaction", .ret_type = 1, .nargs = 3, 299 .args = { { Signal, 0 }, { Sigaction | IN, 1 }, 300 { Sigaction | OUT, 2 } } }, 301 { .name = "sigpending", .ret_type = 1, .nargs = 1, 302 .args = { { Sigset | OUT, 0 } } }, 303 { .name = "sigprocmask", .ret_type = 1, .nargs = 3, 304 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } }, 305 { .name = "sigqueue", .ret_type = 1, .nargs = 3, 306 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } }, 307 { .name = "sigreturn", .ret_type = 1, .nargs = 1, 308 .args = { { Ptr, 0 } } }, 309 { .name = "sigsuspend", .ret_type = 1, .nargs = 1, 310 .args = { { Sigset | IN, 0 } } }, 311 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3, 312 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } }, 313 { .name = "sigwait", .ret_type = 1, .nargs = 2, 314 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } }, 315 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2, 316 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } }, 317 { .name = "socket", .ret_type = 1, .nargs = 3, 318 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } }, 319 { .name = "stat", .ret_type = 1, .nargs = 2, 320 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 321 { .name = "statfs", .ret_type = 1, .nargs = 2, 322 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } }, 323 { .name = "symlink", .ret_type = 1, .nargs = 2, 324 .args = { { Name, 0 }, { Name, 1 } } }, 325 { .name = "symlinkat", .ret_type = 1, .nargs = 3, 326 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } }, 327 { .name = "sysarch", .ret_type = 1, .nargs = 2, 328 .args = { { Sysarch, 0 }, { Ptr, 1 } } }, 329 { .name = "thr_kill", .ret_type = 1, .nargs = 2, 330 .args = { { Long, 0 }, { Signal, 1 } } }, 331 { .name = "thr_self", .ret_type = 1, .nargs = 1, 332 .args = { { Ptr, 0 } } }, 333 { .name = "truncate", .ret_type = 1, .nargs = 2, 334 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } }, 335#if 0 336 /* Does not exist */ 337 { .name = "umount", .ret_type = 1, .nargs = 2, 338 .args = { { Name, 0 }, { Int, 2 } } }, 339#endif 340 { .name = "unlink", .ret_type = 1, .nargs = 1, 341 .args = { { Name, 0 } } }, 342 { .name = "unlinkat", .ret_type = 1, .nargs = 3, 343 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } }, 344 { .name = "unmount", .ret_type = 1, .nargs = 2, 345 .args = { { Name, 0 }, { Int, 1 } } }, 346 { .name = "utimensat", .ret_type = 1, .nargs = 4, 347 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 }, 348 { Atflags, 3 } } }, 349 { .name = "utimes", .ret_type = 1, .nargs = 2, 350 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 351 { .name = "wait4", .ret_type = 1, .nargs = 4, 352 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 }, 353 { Rusage | OUT, 3 } } }, 354 { .name = "wait6", .ret_type = 1, .nargs = 6, 355 .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN }, 356 { ExitStatus | OUT, 1 + QUAD_ALIGN + QUAD_SLOTS }, 357 { Waitoptions, 2 + QUAD_ALIGN + QUAD_SLOTS }, 358 { Rusage | OUT, 3 + QUAD_ALIGN + QUAD_SLOTS }, 359 { Ptr, 4 + QUAD_ALIGN + QUAD_SLOTS } } }, 360 { .name = "write", .ret_type = 1, .nargs = 3, 361 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } }, 362 363 /* Linux ABI */ 364 { .name = "linux_access", .ret_type = 1, .nargs = 2, 365 .args = { { Name, 0 }, { Accessmode, 1 } } }, 366 { .name = "linux_execve", .ret_type = 1, .nargs = 3, 367 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 }, 368 { ExecEnv | IN, 2 } } }, 369 { .name = "linux_lseek", .ret_type = 2, .nargs = 3, 370 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } }, 371 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2, 372 .args = { { Name | IN, 0 }, { Int, 1 } } }, 373 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2, 374 .args = { { Int, 0 }, { Ptr | OUT, 1 } } }, 375 { .name = "linux_newstat", .ret_type = 1, .nargs = 2, 376 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, 377 { .name = "linux_open", .ret_type = 1, .nargs = 3, 378 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } }, 379 { .name = "linux_readlink", .ret_type = 1, .nargs = 3, 380 .args = { { Name, 0 }, { Name | OUT, 1 }, { Int, 2 } } }, 381 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2, 382 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } }, 383 { .name = "linux_stat64", .ret_type = 1, .nargs = 3, 384 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } }, 385 386 { .name = 0 }, 387}; 388static STAILQ_HEAD(, syscall) syscalls; 389 390/* Xlat idea taken from strace */ 391struct xlat { 392 int val; 393 const char *str; 394}; 395 396#define X(a) { a, #a }, 397#define XEND { 0, NULL } 398 399static struct xlat kevent_filters[] = { 400 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE) 401 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER) 402 X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER) XEND 403}; 404 405static struct xlat kevent_flags[] = { 406 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT) 407 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) 408 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND 409}; 410 411static struct xlat kevent_user_ffctrl[] = { 412 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY) 413 XEND 414}; 415 416static struct xlat kevent_rdwr_fflags[] = { 417 X(NOTE_LOWAT) XEND 418}; 419 420static struct xlat kevent_vnode_fflags[] = { 421 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB) 422 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND 423}; 424 425static struct xlat kevent_proc_fflags[] = { 426 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR) 427 X(NOTE_CHILD) XEND 428}; 429 430static struct xlat kevent_timer_fflags[] = { 431 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS) 432 XEND 433}; 434 435static struct xlat poll_flags[] = { 436 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR) 437 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND) 438 X(POLLWRBAND) X(POLLINIGNEOF) XEND 439}; 440 441static struct xlat mmap_flags[] = { 442 X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME) 443 X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100) 444 X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON) 445 X(MAP_EXCL) X(MAP_NOCORE) X(MAP_PREFAULT_READ) 446#ifdef MAP_32BIT 447 X(MAP_32BIT) 448#endif 449 XEND 450}; 451 452static struct xlat mprot_flags[] = { 453 X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND 454}; 455 456static struct xlat whence_arg[] = { 457 X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) X(SEEK_DATA) X(SEEK_HOLE) XEND 458}; 459 460static struct xlat sigaction_flags[] = { 461 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) 462 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND 463}; 464 465static struct xlat fcntl_arg[] = { 466 X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL) 467 X(F_GETOWN) X(F_SETOWN) X(F_OGETLK) X(F_OSETLK) X(F_OSETLKW) 468 X(F_DUP2FD) X(F_GETLK) X(F_SETLK) X(F_SETLKW) X(F_SETLK_REMOTE) 469 X(F_READAHEAD) X(F_RDAHEAD) X(F_DUPFD_CLOEXEC) X(F_DUP2FD_CLOEXEC) 470 XEND 471}; 472 473static struct xlat fcntlfd_arg[] = { 474 X(FD_CLOEXEC) XEND 475}; 476 477static struct xlat fcntlfl_arg[] = { 478 X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW) 479 X(FRDAHEAD) X(O_DIRECT) XEND 480}; 481 482static struct xlat sockdomain_arg[] = { 483 X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK) 484 X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI) 485 X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet) 486 X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE) 487 X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX) 488 X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6) 489 X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER) 490 X(PF_ARP) X(PF_BLUETOOTH) X(PF_IEEE80211) X(PF_INET_SDP) 491 X(PF_INET6_SDP) XEND 492}; 493 494static struct xlat socktype_arg[] = { 495 X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM) 496 X(SOCK_SEQPACKET) XEND 497}; 498 499static struct xlat open_flags[] = { 500 X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK) 501 X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC) 502 X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY) 503 X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC) 504 XEND 505}; 506 507static struct xlat shutdown_arg[] = { 508 X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND 509}; 510 511static struct xlat resource_arg[] = { 512 X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK) 513 X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC) 514 X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) X(RLIMIT_NPTS) 515 X(RLIMIT_SWAP) XEND 516}; 517 518static struct xlat pathconf_arg[] = { 519 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT) 520 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF) 521 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE) 522 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO) 523 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS) 524 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE) 525 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN) 526 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX) 527 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT) 528 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND 529}; 530 531static struct xlat rfork_flags[] = { 532 X(RFFDG) X(RFPROC) X(RFMEM) X(RFNOWAIT) X(RFCFDG) X(RFTHREAD) 533 X(RFSIGSHARE) X(RFLINUXTHPN) X(RFTSIGZMB) X(RFPPWAIT) XEND 534}; 535 536static struct xlat wait_options[] = { 537 X(WNOHANG) X(WUNTRACED) X(WCONTINUED) X(WNOWAIT) X(WEXITED) 538 X(WTRAPPED) XEND 539}; 540 541static struct xlat idtype_arg[] = { 542 X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID) 543 X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID) 544 X(P_CTID) X(P_CPUID) X(P_PSETID) XEND 545}; 546 547static struct xlat procctl_arg[] = { 548 X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE) 549 X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL) 550 X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND 551}; 552 553static struct xlat umtx_ops[] = { 554 X(UMTX_OP_LOCK) X(UMTX_OP_UNLOCK) X(UMTX_OP_WAIT) 555 X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK) 556 X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT) 557 X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT) 558 X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK) 559 X(UMTX_OP_WAIT_UINT_PRIVATE) X(UMTX_OP_WAKE_PRIVATE) 560 X(UMTX_OP_MUTEX_WAIT) X(UMTX_OP_MUTEX_WAKE) X(UMTX_OP_SEM_WAIT) 561 X(UMTX_OP_SEM_WAKE) X(UMTX_OP_NWAKE_PRIVATE) X(UMTX_OP_MUTEX_WAKE2) 562 XEND 563}; 564 565static struct xlat at_flags[] = { 566 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW) 567 X(AT_REMOVEDIR) XEND 568}; 569 570static struct xlat access_modes[] = { 571 X(R_OK) X(W_OK) X(X_OK) XEND 572}; 573 574static struct xlat sysarch_ops[] = { 575#if defined(__i386__) || defined(__amd64__) 576 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM) 577 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE) 578 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE) 579 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE) 580 X(AMD64_GET_XFPUSTATE) 581#endif 582 XEND 583}; 584 585static struct xlat linux_socketcall_ops[] = { 586 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN) 587 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME) 588 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO) 589 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT) 590 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG) 591 XEND 592}; 593 594static struct xlat sigprocmask_ops[] = { 595 X(SIG_BLOCK) X(SIG_UNBLOCK) X(SIG_SETMASK) 596 XEND 597}; 598 599#undef X 600#undef XEND 601 602/* 603 * Searches an xlat array for a value, and returns it if found. Otherwise 604 * return a string representation. 605 */ 606static const char * 607lookup(struct xlat *xlat, int val, int base) 608{ 609 static char tmp[16]; 610 611 for (; xlat->str != NULL; xlat++) 612 if (xlat->val == val) 613 return (xlat->str); 614 switch (base) { 615 case 8: 616 sprintf(tmp, "0%o", val); 617 break; 618 case 16: 619 sprintf(tmp, "0x%x", val); 620 break; 621 case 10: 622 sprintf(tmp, "%u", val); 623 break; 624 default: 625 errx(1,"Unknown lookup base"); 626 break; 627 } 628 return (tmp); 629} 630 631static const char * 632xlookup(struct xlat *xlat, int val) 633{ 634 635 return (lookup(xlat, val, 16)); 636} 637 638/* 639 * Searches an xlat array containing bitfield values. Remaining bits 640 * set after removing the known ones are printed at the end: 641 * IN|0x400. 642 */ 643static char * 644xlookup_bits(struct xlat *xlat, int val) 645{ 646 int len, rem; 647 static char str[512]; 648 649 len = 0; 650 rem = val; 651 for (; xlat->str != NULL; xlat++) { 652 if ((xlat->val & rem) == xlat->val) { 653 /* 654 * Don't print the "all-bits-zero" string unless all 655 * bits are really zero. 656 */ 657 if (xlat->val == 0 && val != 0) 658 continue; 659 len += sprintf(str + len, "%s|", xlat->str); 660 rem &= ~(xlat->val); 661 } 662 } 663 664 /* 665 * If we have leftover bits or didn't match anything, print 666 * the remainder. 667 */ 668 if (rem || len == 0) 669 len += sprintf(str + len, "0x%x", rem); 670 if (len && str[len - 1] == '|') 671 len--; 672 str[len] = 0; 673 return (str); 674} 675 676void 677init_syscalls(void) 678{ 679 struct syscall *sc; 680 681 STAILQ_INIT(&syscalls); 682 for (sc = decoded_syscalls; sc->name != NULL; sc++) 683 STAILQ_INSERT_HEAD(&syscalls, sc, entries); 684} 685/* 686 * If/when the list gets big, it might be desirable to do it 687 * as a hash table or binary search. 688 */ 689struct syscall * 690get_syscall(const char *name, int nargs) 691{ 692 struct syscall *sc; 693 int i; 694 695 if (name == NULL) 696 return (NULL); 697 STAILQ_FOREACH(sc, &syscalls, entries) 698 if (strcmp(name, sc->name) == 0) 699 return (sc); 700 701 /* It is unknown. Add it into the list. */ 702#if DEBUG 703 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name, 704 nargs); 705#endif 706 707 sc = calloc(1, sizeof(struct syscall)); 708 sc->name = strdup(name); 709 sc->ret_type = 1; 710 sc->nargs = nargs; 711 for (i = 0; i < nargs; i++) { 712 sc->args[i].offset = i; 713 /* Treat all unknown arguments as LongHex. */ 714 sc->args[i].type = LongHex; 715 } 716 STAILQ_INSERT_HEAD(&syscalls, sc, entries); 717 718 return (sc); 719} 720 721/* 722 * Copy a fixed amount of bytes from the process. 723 */ 724static int 725get_struct(pid_t pid, void *offset, void *buf, int len) 726{ 727 struct ptrace_io_desc iorequest; 728 729 iorequest.piod_op = PIOD_READ_D; 730 iorequest.piod_offs = offset; 731 iorequest.piod_addr = buf; 732 iorequest.piod_len = len; 733 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) 734 return (-1); 735 return (0); 736} 737 738#define MAXSIZE 4096 739 740/* 741 * Copy a string from the process. Note that it is 742 * expected to be a C string, but if max is set, it will 743 * only get that much. 744 */ 745static char * 746get_string(pid_t pid, void *addr, int max) 747{ 748 struct ptrace_io_desc iorequest; 749 char *buf, *nbuf; 750 size_t offset, size, totalsize; 751 752 offset = 0; 753 if (max) 754 size = max + 1; 755 else { 756 /* Read up to the end of the current page. */ 757 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE); 758 if (size > MAXSIZE) 759 size = MAXSIZE; 760 } 761 totalsize = size; 762 buf = malloc(totalsize); 763 if (buf == NULL) 764 return (NULL); 765 for (;;) { 766 iorequest.piod_op = PIOD_READ_D; 767 iorequest.piod_offs = (char *)addr + offset; 768 iorequest.piod_addr = buf + offset; 769 iorequest.piod_len = size; 770 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) { 771 free(buf); 772 return (NULL); 773 } 774 if (memchr(buf + offset, '\0', size) != NULL) 775 return (buf); 776 offset += size; 777 if (totalsize < MAXSIZE && max == 0) { 778 size = MAXSIZE - totalsize; 779 if (size > PAGE_SIZE) 780 size = PAGE_SIZE; 781 nbuf = realloc(buf, totalsize + size); 782 if (nbuf == NULL) { 783 buf[totalsize - 1] = '\0'; 784 return (buf); 785 } 786 buf = nbuf; 787 totalsize += size; 788 } else { 789 buf[totalsize - 1] = '\0'; 790 return (buf); 791 } 792 } 793} 794 795static char * 796strsig2(int sig) 797{ 798 static char tmp[sizeof(int) * 3 + 1]; 799 char *ret; 800 801 ret = strsig(sig); 802 if (ret == NULL) { 803 snprintf(tmp, sizeof(tmp), "%d", sig); 804 ret = tmp; 805 } 806 return (ret); 807} 808 809static void 810print_kevent(FILE *fp, struct kevent *ke, int input) 811{ 812 813 switch (ke->filter) { 814 case EVFILT_READ: 815 case EVFILT_WRITE: 816 case EVFILT_VNODE: 817 case EVFILT_PROC: 818 case EVFILT_TIMER: 819 fprintf(fp, "%ju", (uintmax_t)ke->ident); 820 break; 821 case EVFILT_SIGNAL: 822 fputs(strsig2(ke->ident), fp); 823 break; 824 default: 825 fprintf(fp, "%p", (void *)ke->ident); 826 } 827 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter), 828 xlookup_bits(kevent_flags, ke->flags)); 829 switch (ke->filter) { 830 case EVFILT_READ: 831 case EVFILT_WRITE: 832 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp); 833 break; 834 case EVFILT_VNODE: 835 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp); 836 break; 837 case EVFILT_PROC: 838 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp); 839 break; 840 case EVFILT_TIMER: 841 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp); 842 break; 843 case EVFILT_USER: { 844 int ctrl, data; 845 846 ctrl = ke->fflags & NOTE_FFCTRLMASK; 847 data = ke->fflags & NOTE_FFLAGSMASK; 848 if (input) { 849 fputs(xlookup(kevent_user_ffctrl, ctrl), fp); 850 if (ke->fflags & NOTE_TRIGGER) 851 fputs("|NOTE_TRIGGER", fp); 852 if (data != 0) 853 fprintf(fp, "|%#x", data); 854 } else { 855 fprintf(fp, "%#x", data); 856 } 857 break; 858 } 859 default: 860 fprintf(fp, "%#x", ke->fflags); 861 } 862 fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata); 863} 864 865/* 866 * Converts a syscall argument into a string. Said string is 867 * allocated via malloc(), so needs to be free()'d. sc is 868 * a pointer to the syscall description (see above); args is 869 * an array of all of the system call arguments. 870 */ 871char * 872print_arg(struct syscall_args *sc, unsigned long *args, long *retval, 873 struct trussinfo *trussinfo) 874{ 875 FILE *fp; 876 char *tmp; 877 size_t tmplen; 878 pid_t pid; 879 880 fp = open_memstream(&tmp, &tmplen); 881 pid = trussinfo->curthread->proc->pid; 882 switch (sc->type & ARG_MASK) { 883 case Hex: 884 fprintf(fp, "0x%x", (int)args[sc->offset]); 885 break; 886 case Octal: 887 fprintf(fp, "0%o", (int)args[sc->offset]); 888 break; 889 case Int: 890 fprintf(fp, "%d", (int)args[sc->offset]); 891 break; 892 case LongHex: 893 fprintf(fp, "0x%lx", args[sc->offset]); 894 break; 895 case Long: 896 fprintf(fp, "%ld", args[sc->offset]); 897 break; 898 case Name: { 899 /* NULL-terminated string. */ 900 char *tmp2; 901 902 tmp2 = get_string(pid, (void*)args[sc->offset], 0); 903 fprintf(fp, "\"%s\"", tmp2); 904 free(tmp2); 905 break; 906 } 907 case BinString: { 908 /* 909 * Binary block of data that might have printable characters. 910 * XXX If type|OUT, assume that the length is the syscall's 911 * return value. Otherwise, assume that the length of the block 912 * is in the next syscall argument. 913 */ 914 int max_string = trussinfo->strsize; 915 char tmp2[max_string + 1], *tmp3; 916 int len; 917 int truncated = 0; 918 919 if (sc->type & OUT) 920 len = retval[0]; 921 else 922 len = args[sc->offset + 1]; 923 924 /* 925 * Don't print more than max_string characters, to avoid word 926 * wrap. If we have to truncate put some ... after the string. 927 */ 928 if (len > max_string) { 929 len = max_string; 930 truncated = 1; 931 } 932 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) 933 != -1) { 934 tmp3 = malloc(len * 4 + 1); 935 while (len) { 936 if (strvisx(tmp3, tmp2, len, 937 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 938 break; 939 len--; 940 truncated = 1; 941 }; 942 fprintf(fp, "\"%s\"%s", tmp3, truncated ? 943 "..." : ""); 944 free(tmp3); 945 } else { 946 fprintf(fp, "0x%lx", args[sc->offset]); 947 } 948 break; 949 } 950 case ExecArgs: 951 case ExecEnv: 952 case StringArray: { 953 uintptr_t addr; 954 union { 955 char *strarray[0]; 956 char buf[PAGE_SIZE]; 957 } u; 958 char *string; 959 size_t len; 960 u_int first, i; 961 962 /* 963 * Only parse argv[] and environment arrays from exec calls 964 * if requested. 965 */ 966 if (((sc->type & ARG_MASK) == ExecArgs && 967 (trussinfo->flags & EXECVEARGS) == 0) || 968 ((sc->type & ARG_MASK) == ExecEnv && 969 (trussinfo->flags & EXECVEENVS) == 0)) { 970 fprintf(fp, "0x%lx", args[sc->offset]); 971 break; 972 } 973 974 /* 975 * Read a page of pointers at a time. Punt if the top-level 976 * pointer is not aligned. Note that the first read is of 977 * a partial page. 978 */ 979 addr = args[sc->offset]; 980 if (addr % sizeof(char *) != 0) { 981 fprintf(fp, "0x%lx", args[sc->offset]); 982 break; 983 } 984 985 len = PAGE_SIZE - (addr & PAGE_MASK); 986 if (get_struct(pid, (void *)addr, u.buf, len) == -1) { 987 fprintf(fp, "0x%lx", args[sc->offset]); 988 break; 989 } 990 991 fputc('[', fp); 992 first = 1; 993 i = 0; 994 while (u.strarray[i] != NULL) { 995 string = get_string(pid, u.strarray[i], 0); 996 fprintf(fp, "%s \"%s\"", first ? "" : ",", string); 997 free(string); 998 first = 0; 999 1000 i++; 1001 if (i == len / sizeof(char *)) { 1002 addr += len; 1003 len = PAGE_SIZE; 1004 if (get_struct(pid, (void *)addr, u.buf, len) == 1005 -1) { 1006 fprintf(fp, ", <inval>"); 1007 break; 1008 } 1009 i = 0; 1010 } 1011 } 1012 fputs(" ]", fp); 1013 break; 1014 } 1015#ifdef __LP64__ 1016 case Quad: 1017 fprintf(fp, "%ld", args[sc->offset]); 1018 break; 1019 case QuadHex: 1020 fprintf(fp, "0x%lx", args[sc->offset]); 1021 break; 1022#else 1023 case Quad: 1024 case QuadHex: { 1025 unsigned long long ll; 1026 1027#if _BYTE_ORDER == _LITTLE_ENDIAN 1028 ll = (unsigned long long)args[sc->offset + 1] << 32 | 1029 args[sc->offset]; 1030#else 1031 ll = (unsigned long long)args[sc->offset] << 32 | 1032 args[sc->offset + 1]; 1033#endif 1034 if ((sc->type & ARG_MASK) == Quad) 1035 fprintf(fp, "%lld", ll); 1036 else 1037 fprintf(fp, "0x%llx", ll); 1038 break; 1039 } 1040#endif 1041 case Ptr: 1042 fprintf(fp, "0x%lx", args[sc->offset]); 1043 break; 1044 case Readlinkres: { 1045 char *tmp2; 1046 1047 if (retval[0] == -1) 1048 break; 1049 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]); 1050 fprintf(fp, "\"%s\"", tmp2); 1051 free(tmp2); 1052 break; 1053 } 1054 case Ioctl: { 1055 const char *temp; 1056 unsigned long cmd; 1057 1058 cmd = args[sc->offset]; 1059 temp = ioctlname(cmd); 1060 if (temp) 1061 fputs(temp, fp); 1062 else { 1063 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 1064 cmd, cmd & IOC_OUT ? "R" : "", 1065 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd), 1066 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?', 1067 cmd & 0xFF, IOCPARM_LEN(cmd)); 1068 } 1069 break; 1070 } 1071 case Umtx: { 1072 struct umtx umtx; 1073 if (get_struct(pid, (void *)args[sc->offset], &umtx, 1074 sizeof(umtx)) != -1) 1075 fprintf(fp, "{ 0x%lx }", (long)umtx.u_owner); 1076 else 1077 fprintf(fp, "0x%lx", args[sc->offset]); 1078 break; 1079 } 1080 case Timespec: { 1081 struct timespec ts; 1082 1083 if (get_struct(pid, (void *)args[sc->offset], &ts, 1084 sizeof(ts)) != -1) 1085 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec, 1086 ts.tv_nsec); 1087 else 1088 fprintf(fp, "0x%lx", args[sc->offset]); 1089 break; 1090 } 1091 case Timespec2: { 1092 struct timespec ts[2]; 1093 const char *sep; 1094 unsigned int i; 1095 1096 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) 1097 != -1) { 1098 fputs("{ ", fp); 1099 sep = ""; 1100 for (i = 0; i < nitems(ts); i++) { 1101 fputs(sep, fp); 1102 sep = ", "; 1103 switch (ts[i].tv_nsec) { 1104 case UTIME_NOW: 1105 fprintf(fp, "UTIME_NOW"); 1106 break; 1107 case UTIME_OMIT: 1108 fprintf(fp, "UTIME_OMIT"); 1109 break; 1110 default: 1111 fprintf(fp, "%jd.%09ld", 1112 (intmax_t)ts[i].tv_sec, 1113 ts[i].tv_nsec); 1114 break; 1115 } 1116 } 1117 fputs(" }", fp); 1118 } else 1119 fprintf(fp, "0x%lx", args[sc->offset]); 1120 break; 1121 } 1122 case Timeval: { 1123 struct timeval tv; 1124 1125 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1126 != -1) 1127 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec, 1128 tv.tv_usec); 1129 else 1130 fprintf(fp, "0x%lx", args[sc->offset]); 1131 break; 1132 } 1133 case Timeval2: { 1134 struct timeval tv[2]; 1135 1136 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 1137 != -1) 1138 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1139 (intmax_t)tv[0].tv_sec, tv[0].tv_usec, 1140 (intmax_t)tv[1].tv_sec, tv[1].tv_usec); 1141 else 1142 fprintf(fp, "0x%lx", args[sc->offset]); 1143 break; 1144 } 1145 case Itimerval: { 1146 struct itimerval itv; 1147 1148 if (get_struct(pid, (void *)args[sc->offset], &itv, 1149 sizeof(itv)) != -1) 1150 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }", 1151 (intmax_t)itv.it_interval.tv_sec, 1152 itv.it_interval.tv_usec, 1153 (intmax_t)itv.it_value.tv_sec, 1154 itv.it_value.tv_usec); 1155 else 1156 fprintf(fp, "0x%lx", args[sc->offset]); 1157 break; 1158 } 1159 case LinuxSockArgs: 1160 { 1161 struct linux_socketcall_args largs; 1162 1163 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs, 1164 sizeof(largs)) != -1) 1165 fprintf(fp, "{ %s, 0x%lx }", 1166 lookup(linux_socketcall_ops, largs.what, 10), 1167 (long unsigned int)largs.args); 1168 else 1169 fprintf(fp, "0x%lx", args[sc->offset]); 1170 break; 1171 } 1172 case Pollfd: { 1173 /* 1174 * XXX: A Pollfd argument expects the /next/ syscall argument 1175 * to be the number of fds in the array. This matches the poll 1176 * syscall. 1177 */ 1178 struct pollfd *pfd; 1179 int numfds = args[sc->offset + 1]; 1180 size_t bytes = sizeof(struct pollfd) * numfds; 1181 int i; 1182 1183 if ((pfd = malloc(bytes)) == NULL) 1184 err(1, "Cannot malloc %zu bytes for pollfd array", 1185 bytes); 1186 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) 1187 != -1) { 1188 fputs("{", fp); 1189 for (i = 0; i < numfds; i++) { 1190 fprintf(fp, " %d/%s", pfd[i].fd, 1191 xlookup_bits(poll_flags, pfd[i].events)); 1192 } 1193 fputs(" }", fp); 1194 } else { 1195 fprintf(fp, "0x%lx", args[sc->offset]); 1196 } 1197 free(pfd); 1198 break; 1199 } 1200 case Fd_set: { 1201 /* 1202 * XXX: A Fd_set argument expects the /first/ syscall argument 1203 * to be the number of fds in the array. This matches the 1204 * select syscall. 1205 */ 1206 fd_set *fds; 1207 int numfds = args[0]; 1208 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 1209 int i; 1210 1211 if ((fds = malloc(bytes)) == NULL) 1212 err(1, "Cannot malloc %zu bytes for fd_set array", 1213 bytes); 1214 if (get_struct(pid, (void *)args[sc->offset], fds, bytes) 1215 != -1) { 1216 fputs("{", fp); 1217 for (i = 0; i < numfds; i++) { 1218 if (FD_ISSET(i, fds)) 1219 fprintf(fp, " %d", i); 1220 } 1221 fputs(" }", fp); 1222 } else 1223 fprintf(fp, "0x%lx", args[sc->offset]); 1224 free(fds); 1225 break; 1226 } 1227 case Signal: 1228 fputs(strsig2(args[sc->offset]), fp); 1229 break; 1230 case Sigset: { 1231 long sig; 1232 sigset_t ss; 1233 int i, first; 1234 1235 sig = args[sc->offset]; 1236 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 1237 sizeof(ss)) == -1) { 1238 fprintf(fp, "0x%lx", args[sc->offset]); 1239 break; 1240 } 1241 fputs("{ ", fp); 1242 first = 1; 1243 for (i = 1; i < sys_nsig; i++) { 1244 if (sigismember(&ss, i)) { 1245 fprintf(fp, "%s%s", !first ? "|" : "", 1246 strsig(i)); 1247 first = 0; 1248 } 1249 } 1250 if (!first) 1251 fputc(' ', fp); 1252 fputc('}', fp); 1253 break; 1254 } 1255 case Sigprocmask: { 1256 fputs(xlookup(sigprocmask_ops, args[sc->offset]), fp); 1257 break; 1258 } 1259 case Fcntlflag: { 1260 /* XXX: Output depends on the value of the previous argument. */ 1261 switch (args[sc->offset - 1]) { 1262 case F_SETFD: 1263 fputs(xlookup_bits(fcntlfd_arg, args[sc->offset]), fp); 1264 break; 1265 case F_SETFL: 1266 fputs(xlookup_bits(fcntlfl_arg, args[sc->offset]), fp); 1267 break; 1268 case F_GETFD: 1269 case F_GETFL: 1270 case F_GETOWN: 1271 break; 1272 default: 1273 fprintf(fp, "0x%lx", args[sc->offset]); 1274 break; 1275 } 1276 break; 1277 } 1278 case Open: 1279 fputs(xlookup_bits(open_flags, args[sc->offset]), fp); 1280 break; 1281 case Fcntl: 1282 fputs(xlookup(fcntl_arg, args[sc->offset]), fp); 1283 break; 1284 case Mprot: 1285 fputs(xlookup_bits(mprot_flags, args[sc->offset]), fp); 1286 break; 1287 case Mmapflags: { 1288 int align, flags; 1289 1290 /* 1291 * MAP_ALIGNED can't be handled by xlookup_bits(), so 1292 * generate that string manually and prepend it to the 1293 * string from xlookup_bits(). Have to be careful to 1294 * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is 1295 * the only flag. 1296 */ 1297 flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK; 1298 align = args[sc->offset] & MAP_ALIGNMENT_MASK; 1299 if (align != 0) { 1300 if (align == MAP_ALIGNED_SUPER) 1301 fputs("MAP_ALIGNED_SUPER", fp); 1302 else 1303 fprintf(fp, "MAP_ALIGNED(%d)", 1304 align >> MAP_ALIGNMENT_SHIFT); 1305 if (flags == 0) 1306 break; 1307 fputc('|', fp); 1308 } 1309 fputs(xlookup_bits(mmap_flags, flags), fp); 1310 break; 1311 } 1312 case Whence: 1313 fputs(xlookup(whence_arg, args[sc->offset]), fp); 1314 break; 1315 case Sockdomain: 1316 fputs(xlookup(sockdomain_arg, args[sc->offset]), fp); 1317 break; 1318 case Socktype: { 1319 int type, flags; 1320 1321 flags = args[sc->offset] & (SOCK_CLOEXEC | SOCK_NONBLOCK); 1322 type = args[sc->offset] & ~flags; 1323 fputs(xlookup(socktype_arg, type), fp); 1324 if (flags & SOCK_CLOEXEC) 1325 fprintf(fp, "|SOCK_CLOEXEC"); 1326 if (flags & SOCK_NONBLOCK) 1327 fprintf(fp, "|SOCK_NONBLOCK"); 1328 break; 1329 } 1330 case Shutdown: 1331 fputs(xlookup(shutdown_arg, args[sc->offset]), fp); 1332 break; 1333 case Resource: 1334 fputs(xlookup(resource_arg, args[sc->offset]), fp); 1335 break; 1336 case Pathconf: 1337 fputs(xlookup(pathconf_arg, args[sc->offset]), fp); 1338 break; 1339 case Rforkflags: 1340 fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp); 1341 break; 1342 case Sockaddr: { 1343 char addr[64]; 1344 struct sockaddr_in *lsin; 1345 struct sockaddr_in6 *lsin6; 1346 struct sockaddr_un *sun; 1347 struct sockaddr *sa; 1348 socklen_t len; 1349 u_char *q; 1350 1351 if (args[sc->offset] == 0) { 1352 fputs("NULL", fp); 1353 break; 1354 } 1355 1356 /* 1357 * Extract the address length from the next argument. If 1358 * this is an output sockaddr (OUT is set), then the 1359 * next argument is a pointer to a socklen_t. Otherwise 1360 * the next argument contains a socklen_t by value. 1361 */ 1362 if (sc->type & OUT) { 1363 if (get_struct(pid, (void *)args[sc->offset + 1], 1364 &len, sizeof(len)) == -1) { 1365 fprintf(fp, "0x%lx", args[sc->offset]); 1366 break; 1367 } 1368 } else 1369 len = args[sc->offset + 1]; 1370 1371 /* If the length is too small, just bail. */ 1372 if (len < sizeof(*sa)) { 1373 fprintf(fp, "0x%lx", args[sc->offset]); 1374 break; 1375 } 1376 1377 sa = calloc(1, len); 1378 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) { 1379 free(sa); 1380 fprintf(fp, "0x%lx", args[sc->offset]); 1381 break; 1382 } 1383 1384 switch (sa->sa_family) { 1385 case AF_INET: 1386 if (len < sizeof(*lsin)) 1387 goto sockaddr_short; 1388 lsin = (struct sockaddr_in *)(void *)sa; 1389 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr)); 1390 fprintf(fp, "{ AF_INET %s:%d }", addr, 1391 htons(lsin->sin_port)); 1392 break; 1393 case AF_INET6: 1394 if (len < sizeof(*lsin6)) 1395 goto sockaddr_short; 1396 lsin6 = (struct sockaddr_in6 *)(void *)sa; 1397 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, 1398 sizeof(addr)); 1399 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr, 1400 htons(lsin6->sin6_port)); 1401 break; 1402 case AF_UNIX: 1403 sun = (struct sockaddr_un *)sa; 1404 fprintf(fp, "{ AF_UNIX \"%.*s\" }", 1405 (int)(len - offsetof(struct sockaddr_un, sun_path)), 1406 sun->sun_path); 1407 break; 1408 default: 1409 sockaddr_short: 1410 fprintf(fp, 1411 "{ sa_len = %d, sa_family = %d, sa_data = {", 1412 (int)sa->sa_len, (int)sa->sa_family); 1413 for (q = (u_char *)sa->sa_data; 1414 q < (u_char *)sa + len; q++) 1415 fprintf(fp, "%s 0x%02x", 1416 q == (u_char *)sa->sa_data ? "" : ",", 1417 *q); 1418 fputs(" } }", fp); 1419 } 1420 free(sa); 1421 break; 1422 } 1423 case Sigaction: { 1424 struct sigaction sa; 1425 1426 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) 1427 != -1) { 1428 fputs("{ ", fp); 1429 if (sa.sa_handler == SIG_DFL) 1430 fputs("SIG_DFL", fp); 1431 else if (sa.sa_handler == SIG_IGN) 1432 fputs("SIG_IGN", fp); 1433 else 1434 fprintf(fp, "%p", sa.sa_handler); 1435 fprintf(fp, " %s ss_t }", 1436 xlookup_bits(sigaction_flags, sa.sa_flags)); 1437 } else 1438 fprintf(fp, "0x%lx", args[sc->offset]); 1439 break; 1440 } 1441 case Kevent: { 1442 /* 1443 * XXX XXX: The size of the array is determined by either the 1444 * next syscall argument, or by the syscall return value, 1445 * depending on which argument number we are. This matches the 1446 * kevent syscall, but luckily that's the only syscall that uses 1447 * them. 1448 */ 1449 struct kevent *ke; 1450 int numevents = -1; 1451 size_t bytes; 1452 int i; 1453 1454 if (sc->offset == 1) 1455 numevents = args[sc->offset+1]; 1456 else if (sc->offset == 3 && retval[0] != -1) 1457 numevents = retval[0]; 1458 1459 if (numevents >= 0) { 1460 bytes = sizeof(struct kevent) * numevents; 1461 if ((ke = malloc(bytes)) == NULL) 1462 err(1, 1463 "Cannot malloc %zu bytes for kevent array", 1464 bytes); 1465 } else 1466 ke = NULL; 1467 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 1468 ke, bytes) != -1) { 1469 fputc('{', fp); 1470 for (i = 0; i < numevents; i++) { 1471 fputc(' ', fp); 1472 print_kevent(fp, &ke[i], sc->offset == 1); 1473 } 1474 fputs(" }", fp); 1475 } else { 1476 fprintf(fp, "0x%lx", args[sc->offset]); 1477 } 1478 free(ke); 1479 break; 1480 } 1481 case Stat: { 1482 struct stat st; 1483 1484 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 1485 != -1) { 1486 char mode[12]; 1487 1488 strmode(st.st_mode, mode); 1489 fprintf(fp, 1490 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode, 1491 (uintmax_t)st.st_ino, (intmax_t)st.st_size, 1492 (long)st.st_blksize); 1493 } else { 1494 fprintf(fp, "0x%lx", args[sc->offset]); 1495 } 1496 break; 1497 } 1498 case StatFs: { 1499 unsigned int i; 1500 struct statfs buf; 1501 1502 if (get_struct(pid, (void *)args[sc->offset], &buf, 1503 sizeof(buf)) != -1) { 1504 char fsid[17]; 1505 1506 bzero(fsid, sizeof(fsid)); 1507 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) { 1508 for (i = 0; i < sizeof(buf.f_fsid); i++) 1509 snprintf(&fsid[i*2], 1510 sizeof(fsid) - (i*2), "%02x", 1511 ((u_char *)&buf.f_fsid)[i]); 1512 } 1513 fprintf(fp, 1514 "{ fstypename=%s,mntonname=%s,mntfromname=%s," 1515 "fsid=%s }", buf.f_fstypename, buf.f_mntonname, 1516 buf.f_mntfromname, fsid); 1517 } else 1518 fprintf(fp, "0x%lx", args[sc->offset]); 1519 break; 1520 } 1521 1522 case Rusage: { 1523 struct rusage ru; 1524 1525 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) 1526 != -1) { 1527 fprintf(fp, 1528 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }", 1529 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 1530 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 1531 ru.ru_inblock, ru.ru_oublock); 1532 } else 1533 fprintf(fp, "0x%lx", args[sc->offset]); 1534 break; 1535 } 1536 case Rlimit: { 1537 struct rlimit rl; 1538 1539 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) 1540 != -1) { 1541 fprintf(fp, "{ cur=%ju,max=%ju }", 1542 rl.rlim_cur, rl.rlim_max); 1543 } else 1544 fprintf(fp, "0x%lx", args[sc->offset]); 1545 break; 1546 } 1547 case ExitStatus: { 1548 int status; 1549 1550 if (get_struct(pid, (void *)args[sc->offset], &status, 1551 sizeof(status)) != -1) { 1552 fputs("{ ", fp); 1553 if (WIFCONTINUED(status)) 1554 fputs("CONTINUED", fp); 1555 else if (WIFEXITED(status)) 1556 fprintf(fp, "EXITED,val=%d", 1557 WEXITSTATUS(status)); 1558 else if (WIFSIGNALED(status)) 1559 fprintf(fp, "SIGNALED,sig=%s%s", 1560 strsig2(WTERMSIG(status)), 1561 WCOREDUMP(status) ? ",cored" : ""); 1562 else 1563 fprintf(fp, "STOPPED,sig=%s", 1564 strsig2(WTERMSIG(status))); 1565 fputs(" }", fp); 1566 } else 1567 fprintf(fp, "0x%lx", args[sc->offset]); 1568 break; 1569 } 1570 case Waitoptions: 1571 fputs(xlookup_bits(wait_options, args[sc->offset]), fp); 1572 break; 1573 case Idtype: 1574 fputs(xlookup(idtype_arg, args[sc->offset]), fp); 1575 break; 1576 case Procctl: 1577 fputs(xlookup(procctl_arg, args[sc->offset]), fp); 1578 break; 1579 case Umtxop: 1580 fputs(xlookup(umtx_ops, args[sc->offset]), fp); 1581 break; 1582 case Atfd: 1583 if ((int)args[sc->offset] == AT_FDCWD) 1584 fputs("AT_FDCWD", fp); 1585 else 1586 fprintf(fp, "%d", (int)args[sc->offset]); 1587 break; 1588 case Atflags: 1589 fputs(xlookup_bits(at_flags, args[sc->offset]), fp); 1590 break; 1591 case Accessmode: 1592 if (args[sc->offset] == F_OK) 1593 fputs("F_OK", fp); 1594 else 1595 fputs(xlookup_bits(access_modes, args[sc->offset]), fp); 1596 break; 1597 case Sysarch: 1598 fputs(xlookup(sysarch_ops, args[sc->offset]), fp); 1599 break; 1600 case PipeFds: 1601 /* 1602 * The pipe() system call in the kernel returns its 1603 * two file descriptors via return values. However, 1604 * the interface exposed by libc is that pipe() 1605 * accepts a pointer to an array of descriptors. 1606 * Format the output to match the libc API by printing 1607 * the returned file descriptors as a fake argument. 1608 * 1609 * Overwrite the first retval to signal a successful 1610 * return as well. 1611 */ 1612 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]); 1613 retval[0] = 0; 1614 break; 1615 default: 1616 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 1617 } 1618 fclose(fp); 1619 return (tmp); 1620} 1621 1622/* 1623 * Print (to outfile) the system call and its arguments. Note that 1624 * nargs is the number of arguments (not the number of words; this is 1625 * potentially confusing, I know). 1626 */ 1627void 1628print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, 1629 char **s_args) 1630{ 1631 struct timespec timediff; 1632 int i, len; 1633 1634 len = 0; 1635 if (trussinfo->flags & FOLLOWFORKS) 1636 len += fprintf(trussinfo->outfile, "%5d: ", 1637 trussinfo->curthread->proc->pid); 1638 1639 if (name != NULL && (strcmp(name, "execve") == 0 || 1640 strcmp(name, "exit") == 0)) { 1641 clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); 1642 } 1643 1644 if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 1645 timespecsubt(&trussinfo->curthread->after, 1646 &trussinfo->start_time, &timediff); 1647 len += fprintf(trussinfo->outfile, "%jd.%09ld ", 1648 (intmax_t)timediff.tv_sec, timediff.tv_nsec); 1649 } 1650 1651 if (trussinfo->flags & RELATIVETIMESTAMPS) { 1652 timespecsubt(&trussinfo->curthread->after, 1653 &trussinfo->curthread->before, &timediff); 1654 len += fprintf(trussinfo->outfile, "%jd.%09ld ", 1655 (intmax_t)timediff.tv_sec, timediff.tv_nsec); 1656 } 1657 1658 len += fprintf(trussinfo->outfile, "%s(", name); 1659 1660 for (i = 0; i < nargs; i++) { 1661 if (s_args[i]) 1662 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 1663 else 1664 len += fprintf(trussinfo->outfile, 1665 "<missing argument>"); 1666 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 1667 "," : ""); 1668 } 1669 len += fprintf(trussinfo->outfile, ")"); 1670 for (i = 0; i < 6 - (len / 8); i++) 1671 fprintf(trussinfo->outfile, "\t"); 1672} 1673 1674void 1675print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 1676 char **s_args, int errorp, long *retval, struct syscall *sc) 1677{ 1678 struct timespec timediff; 1679 1680 if (trussinfo->flags & COUNTONLY) { 1681 clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); 1682 timespecsubt(&trussinfo->curthread->after, 1683 &trussinfo->curthread->before, &timediff); 1684 timespecadd(&sc->time, &timediff, &sc->time); 1685 sc->ncalls++; 1686 if (errorp) 1687 sc->nerror++; 1688 return; 1689 } 1690 1691 print_syscall(trussinfo, name, nargs, s_args); 1692 fflush(trussinfo->outfile); 1693 if (errorp) 1694 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0], 1695 strerror(retval[0])); 1696#ifndef __LP64__ 1697 else if (sc->ret_type == 2) { 1698 off_t off; 1699 1700#if _BYTE_ORDER == _LITTLE_ENDIAN 1701 off = (off_t)retval[1] << 32 | retval[0]; 1702#else 1703 off = (off_t)retval[0] << 32 | retval[1]; 1704#endif 1705 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off, 1706 (intmax_t)off); 1707 } 1708#endif 1709 else 1710 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0], 1711 retval[0]); 1712} 1713 1714void 1715print_summary(struct trussinfo *trussinfo) 1716{ 1717 struct timespec total = {0, 0}; 1718 struct syscall *sc; 1719 int ncall, nerror; 1720 1721 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 1722 "syscall", "seconds", "calls", "errors"); 1723 ncall = nerror = 0; 1724 STAILQ_FOREACH(sc, &syscalls, entries) 1725 if (sc->ncalls) { 1726 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1727 sc->name, (intmax_t)sc->time.tv_sec, 1728 sc->time.tv_nsec, sc->ncalls, sc->nerror); 1729 timespecadd(&total, &sc->time, &total); 1730 ncall += sc->ncalls; 1731 nerror += sc->nerror; 1732 } 1733 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 1734 "", "-------------", "-------", "-------"); 1735 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1736 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 1737} 1738