]> git.saurik.com Git - apple/system_cmds.git/blame - fs_usage.tproj/fs_usage.c
system_cmds-735.20.1.tar.gz
[apple/system_cmds.git] / fs_usage.tproj / fs_usage.c
CommitLineData
1815bff5 1/*
cf37c299 2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
cf37c299 5 *
2fc1e207
A
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
cf37c299 13 *
1815bff5
A
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2fc1e207
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
cf37c299 21 *
1815bff5
A
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25/*
cf37c299
A
26 * SDKROOT=macosx.internal cc -I`xcrun -sdk macosx.internal --show-sdk-path`/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -Os -lktrace -lutil -o fs_usage fs_usage.c
27 */
1815bff5 28
1815bff5
A
29#include <stdlib.h>
30#include <stdio.h>
31#include <signal.h>
32#include <strings.h>
1815bff5 33#include <fcntl.h>
34d340d7 34#include <aio.h>
1815bff5 35#include <string.h>
b51d5b5f 36#include <dirent.h>
8459d725
A
37#include <libc.h>
38#include <termios.h>
39#include <errno.h>
40#include <err.h>
41#include <libutil.h>
1815bff5 42
cf37c299
A
43#include <ktrace.h>
44#include <assert.h>
45
1815bff5
A
46#include <sys/types.h>
47#include <sys/param.h>
48#include <sys/time.h>
1815bff5 49#include <sys/ioctl.h>
34d340d7
A
50#include <sys/socket.h>
51#include <sys/mman.h>
8459d725 52#include <sys/disk.h>
fc6d9e4b 53#include <sys/file.h>
cf37c299 54#include <sys/fcntl.h>
1815bff5 55
1815bff5 56#import <mach/clock_types.h>
2fc1e207 57#import <mach/mach_time.h>
8459d725 58
cf37c299 59/*
8459d725
A
60 * MAXCOLS controls when extra data kicks in.
61 * MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
8459d725 62 */
34d340d7 63#define MAXCOLS 132
cf37c299 64#define MAX_WIDE_MODE_COLS 264
09fd88e4
A
65#define MAXWIDTH MAX_WIDE_MODE_COLS + 64
66
cf37c299
A
67typedef struct th_info {
68 struct th_info *next;
69 uintptr_t thread;
1815bff5 70
cf37c299
A
71 /* this is needed for execve()/posix_spawn(), because the command name at the end probe is the new name, which we don't want */
72 char command[MAXCOMLEN + 1];
fc6d9e4b 73
cf37c299
A
74 /*
75 * sometimes a syscall can cause multiple VFS_LOOKUPs of the same vnode with multiple paths
76 * (e.g., one absolute, one relative). traditional fs_usage behavior was to display the
77 * *first* lookup, so we need to save it off once we see it.
78 */
79 unsigned long vnodeid; /* the vp of the VFS_LOOKUP we're currently in, 0 if we are not in one */
80 char pathname[MAXPATHLEN];
81 char pathname2[MAXPATHLEN];
82 char *newest_pathname; /* points to pathname2 if it's filled, otherwise pathname if it's filled, otherwise NULL */
83
84 int pid;
85 int type;
86 unsigned long arg1;
87 unsigned long arg2;
88 unsigned long arg3;
89 unsigned long arg4;
90 unsigned long arg5;
91 unsigned long arg6;
92 unsigned long arg7;
93 unsigned long arg8;
94 int waited;
95 uint64_t stime;
96} *th_info_t;
fc6d9e4b 97
cf37c299
A
98struct diskio {
99 struct diskio *next;
100 struct diskio *prev;
101 unsigned long type;
102 unsigned long bp;
103 unsigned long dev;
104 unsigned long blkno;
105 unsigned long iosize;
106 unsigned long io_errno;
107 unsigned long is_meta;
108 uint64_t vnodeid;
109 uintptr_t issuing_thread;
110 pid_t issuing_pid;
111 uintptr_t completion_thread;
112 char issuing_command[MAXCOMLEN + 1];
113 uint64_t issued_time;
114 uint64_t completed_time;
115 struct timeval completed_walltime;
116 uint32_t bc_info;
fc6d9e4b
A
117};
118
8459d725 119#define HASH_SIZE 1024
fc6d9e4b 120#define HASH_MASK (HASH_SIZE - 1)
8459d725 121
cf37c299
A
122void setup_ktrace_callbacks(void);
123void extend_syscall(uintptr_t thread, int type, ktrace_event_t event);
124
125/* printing routines */
126bool check_filter_mode(pid_t pid, th_info_t ti, unsigned long type, int error, int retval, char *sc_name);
127void format_print(th_info_t ti, char *sc_name, ktrace_event_t event, unsigned long type, int format, uint64_t now, uint64_t stime, int waited, const char *pathname, struct diskio *dio);
128
129/* metadata info hash routines */
130void meta_add_name(uint64_t blockno, const char *pathname);
131const char *meta_find_name(uint64_t blockno);
132void meta_delete_all(void);
133
134/* event ("thread info") routines */
135void event_enter(int type, ktrace_event_t event);
136void event_exit(char *sc_name, int type, ktrace_event_t event, int format);
137th_info_t event_find(uintptr_t thread, int type);
138void event_delete(th_info_t ti_to_delete);
139void event_delete_all(void);
140void event_mark_thread_waited(uintptr_t);
141
142/* network fd set routines */
143void fd_set_is_network(pid_t pid, unsigned long fd, bool set);
144bool fd_is_network(pid_t pid, unsigned long fd);
145void fd_clear_pid(pid_t pid);
146void fd_clear_all(void);
147
148/* shared region address lookup routines */
149void init_shared_cache_mapping(void);
150void lookup_name(uint64_t user_addr, char **type, char **name);
151
152/* disk I/O tracking routines */
153struct diskio *diskio_start(unsigned long type, unsigned long bp, unsigned long dev, unsigned long blkno, unsigned long iosize, ktrace_event_t event);
154struct diskio *diskio_find(unsigned long bp);
155struct diskio *diskio_complete(unsigned long bp, unsigned long io_errno, unsigned long resid, uintptr_t thread, uint64_t curtime, struct timeval curtime_wall);
156void diskio_print(struct diskio *dio);
157void diskio_free(struct diskio *dio);
158
159/* disk name routines */
b51d5b5f 160#define NFS_DEV -1
8459d725 161#define CS_DEV -2
cf37c299
A
162char *generate_cs_disk_name(unsigned long dev, char *s);
163char *find_disk_name(unsigned long dev);
164void cache_disk_names(void);
2fc1e207 165
34d340d7
A
166#define CLASS_MASK 0xff000000
167#define CSC_MASK 0xffff0000
168#define BSC_INDEX(type) ((type >> 2) & 0x3fff)
169
34d340d7 170#define MACH_vmfault 0x01300008
b51d5b5f 171#define MACH_pageout 0x01300004
1815bff5
A
172#define MACH_sched 0x01400000
173#define MACH_stkhandoff 0x01400008
ef8ad44b 174#define MACH_idle 0x01400024
1815bff5 175
8459d725
A
176#define BSC_thread_terminate 0x040c05a4
177
fc6d9e4b
A
178#define HFS_update 0x3018000
179#define HFS_modify_block_end 0x3018004
180
8459d725 181#define Throttled 0x3010184
ef8ad44b 182#define SPEC_ioctl 0x3060000
aaff5f01 183#define SPEC_unmap_info 0x3060004
8459d725 184#define proc_exit 0x4010004
ef8ad44b 185
fc6d9e4b
A
186#define BC_IO_HIT 0x03070010
187#define BC_IO_HIT_STALLED 0x03070020
188#define BC_IO_MISS 0x03070040
189#define BC_IO_MISS_CUT_THROUGH 0x03070080
190#define BC_PLAYBACK_IO 0x03070100
191#define BC_STR(s) ( \
192 (s == BC_IO_HIT) ? "HIT" : \
193 (s == BC_IO_HIT_STALLED) ? "STALL" : \
194 (s == BC_IO_MISS) ? "MISS" : \
195 (s == BC_IO_MISS_CUT_THROUGH) ? "CUT" : \
196 (s == BC_PLAYBACK_IO) ? "PLBK" : \
197 (s == 0x0) ? "NONE" : "UNKN" )
198
aaff5f01
A
199#define P_DISKIO_READ (DKIO_READ << 2)
200#define P_DISKIO_ASYNC (DKIO_ASYNC << 2)
201#define P_DISKIO_META (DKIO_META << 2)
202#define P_DISKIO_PAGING (DKIO_PAGING << 2)
203#define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
204#define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
205#define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
fc6d9e4b
A
206#define P_DISKIO_TIER_MASK (DKIO_TIER_MASK << 2)
207#define P_DISKIO_TIER_SHIFT (DKIO_TIER_SHIFT + 2)
aaff5f01
A
208
209#define P_DISKIO (FSDBG_CODE(DBG_DKRW, 0))
210#define P_DISKIO_DONE (P_DISKIO | (DKIO_DONE << 2))
211#define P_DISKIO_TYPE (P_DISKIO | P_DISKIO_READ | P_DISKIO_META | P_DISKIO_PAGING)
34d340d7
A
212#define P_DISKIO_MASK (CSC_MASK | 0x4)
213
aaff5f01
A
214#define P_WrData (P_DISKIO)
215#define P_RdData (P_DISKIO | P_DISKIO_READ)
216#define P_WrMeta (P_DISKIO | P_DISKIO_META)
217#define P_RdMeta (P_DISKIO | P_DISKIO_META | P_DISKIO_READ)
218#define P_PgOut (P_DISKIO | P_DISKIO_PAGING)
219#define P_PgIn (P_DISKIO | P_DISKIO_PAGING | P_DISKIO_READ)
8459d725 220
aaff5f01
A
221#define P_CS_Class 0x0a000000 // DBG_CORESTORAGE
222#define P_CS_Type_Mask 0xfffffff0
223#define P_CS_IO_Done 0x00000004
b51d5b5f 224
aaff5f01
A
225#define P_CS_ReadChunk 0x0a000200 // chopped up request
226#define P_CS_WriteChunk 0x0a000210
227#define P_CS_MetaRead 0x0a000300 // meta data
228#define P_CS_MetaWrite 0x0a000310
229#define P_CS_TransformRead 0x0a000500 // background transform
230#define P_CS_TransformWrite 0x0a000510
231#define P_CS_MigrationRead 0x0a000600 // composite disk block migration
232#define P_CS_MigrationWrite 0x0a000610
233#define P_CS_SYNC_DISK 0x0a010000
b51d5b5f 234
1815bff5 235#define MSC_map_fd 0x010c00ac
20e66415 236
34d340d7 237#define BSC_BASE 0x040C0000
34d340d7 238
20e66415 239// Network related codes
34d340d7
A
240#define BSC_recvmsg 0x040C006C
241#define BSC_sendmsg 0x040C0070
242#define BSC_recvfrom 0x040C0074
243#define BSC_accept 0x040C0078
244#define BSC_select 0x040C0174
245#define BSC_socket 0x040C0184
246#define BSC_connect 0x040C0188
247#define BSC_bind 0x040C01A0
248#define BSC_listen 0x040C01A8
249#define BSC_sendto 0x040C0214
250#define BSC_socketpair 0x040C021C
fc6d9e4b
A
251#define BSC_recvmsg_nocancel 0x040c0644
252#define BSC_sendmsg_nocancel 0x040c0648
253#define BSC_recvfrom_nocancel 0x040c064c
254#define BSC_accept_nocancel 0x040c0650
255#define BSC_connect_nocancel 0x040c0664
256#define BSC_sendto_nocancel 0x040c0674
34d340d7 257
8459d725 258#define BSC_exit 0x040C0004
34d340d7
A
259#define BSC_read 0x040C000C
260#define BSC_write 0x040C0010
261#define BSC_open 0x040C0014
262#define BSC_close 0x040C0018
263#define BSC_link 0x040C0024
264#define BSC_unlink 0x040C0028
265#define BSC_chdir 0x040c0030
266#define BSC_fchdir 0x040c0034
ef8ad44b
A
267#define BSC_mknod 0x040C0038
268#define BSC_chmod 0x040C003C
269#define BSC_chown 0x040C0040
270#define BSC_getfsstat 0x040C0048
271#define BSC_access 0x040C0084
272#define BSC_chflags 0x040C0088
34d340d7
A
273#define BSC_fchflags 0x040C008C
274#define BSC_sync 0x040C0090
275#define BSC_dup 0x040C00A4
276#define BSC_ioctl 0x040C00D8
277#define BSC_revoke 0x040C00E0
cf37c299 278#define BSC_symlink 0x040C00E4
34d340d7
A
279#define BSC_readlink 0x040C00E8
280#define BSC_execve 0x040C00EC
ef8ad44b 281#define BSC_umask 0x040C00F0
34d340d7
A
282#define BSC_chroot 0x040C00F4
283#define BSC_msync 0x040C0104
284#define BSC_dup2 0x040C0168
285#define BSC_fcntl 0x040C0170
cf37c299
A
286#define BSC_fsync 0x040C017C
287#define BSC_readv 0x040C01E0
288#define BSC_writev 0x040C01E4
289#define BSC_fchown 0x040C01EC
290#define BSC_fchmod 0x040C01F0
34d340d7 291#define BSC_rename 0x040C0200
fc6d9e4b 292#define BSC_flock 0x040C020C
cf37c299
A
293#define BSC_mkfifo 0x040C0210
294#define BSC_mkdir 0x040C0220
34d340d7
A
295#define BSC_rmdir 0x040C0224
296#define BSC_utimes 0x040C0228
297#define BSC_futimes 0x040C022C
298#define BSC_pread 0x040C0264
299#define BSC_pwrite 0x040C0268
cf37c299 300#define BSC_statfs 0x040C0274
8459d725
A
301#define BSC_fstatfs 0x040C0278
302#define BSC_unmount 0x040C027C
303#define BSC_mount 0x040C029C
fc6d9e4b 304#define BSC_fdatasync 0x040C02EC
cf37c299
A
305#define BSC_stat 0x040C02F0
306#define BSC_fstat 0x040C02F4
307#define BSC_lstat 0x040C02F8
308#define BSC_pathconf 0x040C02FC
34d340d7
A
309#define BSC_fpathconf 0x040C0300
310#define BSC_getdirentries 0x040C0310
311#define BSC_mmap 0x040c0314
312#define BSC_lseek 0x040c031c
313#define BSC_truncate 0x040C0320
cf37c299 314#define BSC_ftruncate 0x040C0324
34d340d7 315#define BSC_undelete 0x040C0334
cf37c299
A
316#define BSC_open_dprotected_np 0x040C0360
317#define BSC_getattrlist 0x040C0370
318#define BSC_setattrlist 0x040C0374
319#define BSC_getdirentriesattr 0x040C0378
320#define BSC_exchangedata 0x040C037C
321#define BSC_checkuseraccess 0x040C0380
322#define BSC_searchfs 0x040C0384
323#define BSC_delete 0x040C0388
324#define BSC_copyfile 0x040C038C
fc6d9e4b
A
325#define BSC_fgetattrlist 0x040C0390
326#define BSC_fsetattrlist 0x040C0394
34d340d7
A
327#define BSC_getxattr 0x040C03A8
328#define BSC_fgetxattr 0x040C03AC
329#define BSC_setxattr 0x040C03B0
330#define BSC_fsetxattr 0x040C03B4
331#define BSC_removexattr 0x040C03B8
332#define BSC_fremovexattr 0x040C03BC
333#define BSC_listxattr 0x040C03C0
334#define BSC_flistxattr 0x040C03C4
cf37c299
A
335#define BSC_fsctl 0x040C03C8
336#define BSC_posix_spawn 0x040C03D0
337#define BSC_ffsctl 0x040C03D4
34d340d7 338#define BSC_open_extended 0x040C0454
fc6d9e4b 339#define BSC_umask_extended 0x040C0458
34d340d7
A
340#define BSC_stat_extended 0x040C045C
341#define BSC_lstat_extended 0x040C0460
342#define BSC_fstat_extended 0x040C0464
343#define BSC_chmod_extended 0x040C0468
344#define BSC_fchmod_extended 0x040C046C
345#define BSC_access_extended 0x040C0470
346#define BSC_mkfifo_extended 0x040C048C
347#define BSC_mkdir_extended 0x040C0490
34d340d7
A
348#define BSC_aio_fsync 0x040C04E4
349#define BSC_aio_return 0x040C04E8
350#define BSC_aio_suspend 0x040C04EC
351#define BSC_aio_cancel 0x040C04F0
352#define BSC_aio_error 0x040C04F4
353#define BSC_aio_read 0x040C04F8
354#define BSC_aio_write 0x040C04FC
355#define BSC_lio_listio 0x040C0500
ef8ad44b
A
356#define BSC_sendfile 0x040C0544
357#define BSC_stat64 0x040C0548
358#define BSC_fstat64 0x040C054C
359#define BSC_lstat64 0x040C0550
360#define BSC_stat64_extended 0x040C0554
361#define BSC_lstat64_extended 0x040C0558
362#define BSC_fstat64_extended 0x040C055C
363#define BSC_getdirentries64 0x040C0560
364#define BSC_statfs64 0x040C0564
365#define BSC_fstatfs64 0x040C0568
366#define BSC_getfsstat64 0x040C056C
367#define BSC_pthread_chdir 0x040C0570
368#define BSC_pthread_fchdir 0x040C0574
34d340d7
A
369#define BSC_lchown 0x040C05B0
370
371#define BSC_read_nocancel 0x040c0630
372#define BSC_write_nocancel 0x040c0634
373#define BSC_open_nocancel 0x040c0638
374#define BSC_close_nocancel 0x040c063c
34d340d7
A
375#define BSC_msync_nocancel 0x040c0654
376#define BSC_fcntl_nocancel 0x040c0658
377#define BSC_select_nocancel 0x040c065c
378#define BSC_fsync_nocancel 0x040c0660
34d340d7
A
379#define BSC_readv_nocancel 0x040c066c
380#define BSC_writev_nocancel 0x040c0670
34d340d7
A
381#define BSC_pread_nocancel 0x040c0678
382#define BSC_pwrite_nocancel 0x040c067c
cf37c299 383#define BSC_aio_suspend_nocancel 0x40c0694
fc6d9e4b
A
384#define BSC_guarded_open_np 0x040c06e4
385#define BSC_guarded_close_np 0x040c06e8
386
387#define BSC_fsgetpath 0x040c06ac
34d340d7 388
1a7e3f61
A
389#define BSC_getattrlistbulk 0x040c0734
390
cf37c299 391#define BSC_openat 0x040c073c
1a7e3f61
A
392#define BSC_openat_nocancel 0x040c0740
393#define BSC_renameat 0x040c0744
cf37c299
A
394#define BSC_chmodat 0x040c074c
395#define BSC_chownat 0x040c0750
396#define BSC_fstatat 0x040c0754
1a7e3f61 397#define BSC_fstatat64 0x040c0758
cf37c299 398#define BSC_linkat 0x040c075c
1a7e3f61
A
399#define BSC_unlinkat 0x040c0760
400#define BSC_readlinkat 0x040c0764
401#define BSC_symlinkat 0x040c0768
cf37c299 402#define BSC_mkdirat 0x040c076c
1a7e3f61
A
403#define BSC_getattrlistat 0x040c0770
404
34d340d7
A
405#define BSC_msync_extended 0x040e0104
406#define BSC_pread_extended 0x040e0264
407#define BSC_pwrite_extended 0x040e0268
408#define BSC_mmap_extended 0x040e0314
409#define BSC_mmap_extended2 0x040f0314
1815bff5 410
cf37c299 411#define FMT_NOTHING -1
34d340d7
A
412#define FMT_DEFAULT 0
413#define FMT_FD 1
414#define FMT_FD_IO 2
415#define FMT_FD_2 3
416#define FMT_SOCKET 4
417#define FMT_PGIN 5
418#define FMT_PGOUT 6
419#define FMT_CACHEHIT 7
420#define FMT_DISKIO 8
421#define FMT_LSEEK 9
422#define FMT_PREAD 10
423#define FMT_FTRUNC 11
424#define FMT_TRUNC 12
425#define FMT_SELECT 13
426#define FMT_OPEN 14
427#define FMT_AIO_FSYNC 15
428#define FMT_AIO_RETURN 16
429#define FMT_AIO_SUSPEND 17
430#define FMT_AIO_CANCEL 18
431#define FMT_AIO 19
432#define FMT_LIO_LISTIO 20
433#define FMT_MSYNC 21
434#define FMT_FCNTL 22
435#define FMT_ACCESS 23
436#define FMT_CHMOD 24
437#define FMT_FCHMOD 25
438#define FMT_CHMOD_EXT 26
439#define FMT_FCHMOD_EXT 27
440#define FMT_CHFLAGS 28
441#define FMT_FCHFLAGS 29
442#define FMT_IOCTL 30
443#define FMT_MMAP 31
ef8ad44b
A
444#define FMT_UMASK 32
445#define FMT_SENDFILE 33
aaff5f01 446#define FMT_IOCTL_SYNC 34
8459d725
A
447#define FMT_MOUNT 35
448#define FMT_UNMOUNT 36
449#define FMT_DISKIO_CS 37
450#define FMT_SYNC_DISK_CS 38
aaff5f01
A
451#define FMT_IOCTL_UNMAP 39
452#define FMT_UNMAP_INFO 40
fc6d9e4b
A
453#define FMT_HFS_update 41
454#define FMT_FLOCK 42
1a7e3f61
A
455#define FMT_AT 43
456#define FMT_CHMODAT 44
457#define FMT_OPENAT 45
458#define FMT_RENAMEAT 46
9726c137 459#define FMT_IOCTL_SYNCCACHE 47
34d340d7 460
1815bff5 461#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
20e66415 462
cf37c299 463#pragma mark global state
20e66415 464
cf37c299
A
465ktrace_session_t s;
466bool BC_flag = false;
467bool RAW_flag = false;
468bool wideflag = false;
469bool include_waited_flag = false;
470bool want_kernel_task = true;
471dispatch_source_t stop_timer, sigquit_source, sigpipe_source, sighup_source, sigterm_source, sigwinch_source;
472uint64_t mach_time_of_first_event;
473uint64_t start_time_ns = 0;
474uint64_t end_time_ns = UINT64_MAX;
475unsigned int columns = 0;
1815bff5
A
476
477/*
cf37c299
A
478 * Network only or filesystem only output filter
479 * Default of zero means report all activity - no filtering
1815bff5 480 */
cf37c299
A
481#define FILESYS_FILTER 0x01
482#define NETWORK_FILTER 0x02
483#define EXEC_FILTER 0x08
484#define PATHNAME_FILTER 0x10
485#define DISKIO_FILTER 0x20
486#define DEFAULT_DO_NOT_FILTER 0x00
1815bff5 487
cf37c299
A
488int filter_mode = DEFAULT_DO_NOT_FILTER;
489bool show_cachehits = false;
8459d725 490
cf37c299 491#pragma mark syscall lookup table
8459d725 492
cf37c299 493#define MAX_BSD_SYSCALL 526
8459d725 494
cf37c299
A
495struct bsd_syscall {
496 char *sc_name;
497 int sc_format;
498};
8459d725 499
cf37c299
A
500#define NORMAL_SYSCALL(name) \
501 [BSC_INDEX(BSC_##name)] = {#name, FMT_DEFAULT}
502
503#define SYSCALL(name, format) \
504 [BSC_INDEX(BSC_##name)] = {#name, format}
505
506#define SYSCALL_NAMED(name, displayname, format) \
507 [BSC_INDEX(BSC_##name)] = {#displayname, format}
508
509#define SYSCALL_WITH_NOCANCEL(name, format) \
510 [BSC_INDEX(BSC_##name)] = {#name, format}, \
511 [BSC_INDEX(BSC_##name##_nocancel)] = {#name, format}
512
513const struct bsd_syscall bsd_syscalls[MAX_BSD_SYSCALL] = {
514 SYSCALL(sendfile, FMT_FD), /* this should be changed to FMT_SENDFILE once we add an extended info trace event */
515 SYSCALL_WITH_NOCANCEL(recvmsg, FMT_FD_IO),
516 SYSCALL_WITH_NOCANCEL(sendmsg, FMT_FD_IO),
517 SYSCALL_WITH_NOCANCEL(recvfrom, FMT_FD_IO),
518 SYSCALL_WITH_NOCANCEL(sendto, FMT_FD_IO),
519 SYSCALL_WITH_NOCANCEL(select, FMT_SELECT),
520 SYSCALL_WITH_NOCANCEL(accept, FMT_FD_2),
521 SYSCALL(socket, FMT_SOCKET),
522 SYSCALL_WITH_NOCANCEL(connect, FMT_FD),
523 SYSCALL(bind, FMT_FD),
524 SYSCALL(listen, FMT_FD),
525 SYSCALL(mmap, FMT_MMAP),
526 NORMAL_SYSCALL(socketpair),
527 NORMAL_SYSCALL(getxattr),
528 NORMAL_SYSCALL(setxattr),
529 NORMAL_SYSCALL(removexattr),
530 NORMAL_SYSCALL(listxattr),
531 NORMAL_SYSCALL(stat),
532 NORMAL_SYSCALL(stat64),
533 NORMAL_SYSCALL(stat_extended),
534 SYSCALL_NAMED(stat64_extended, stat_extended64, FMT_DEFAULT), /* should be stat64_extended ? */
535 SYSCALL(mount, FMT_MOUNT),
536 SYSCALL(unmount, FMT_UNMOUNT),
537 NORMAL_SYSCALL(exit),
538 NORMAL_SYSCALL(execve),
539 NORMAL_SYSCALL(posix_spawn),
540 SYSCALL_WITH_NOCANCEL(open, FMT_OPEN),
541 SYSCALL(open_extended, FMT_OPEN),
542 SYSCALL(guarded_open_np, FMT_OPEN),
543 SYSCALL_NAMED(open_dprotected_np, open_dprotected, FMT_OPEN),
544 SYSCALL(dup, FMT_FD_2),
545 SYSCALL(dup2, FMT_FD_2),
546 SYSCALL_WITH_NOCANCEL(close, FMT_FD),
547 SYSCALL(guarded_close_np, FMT_FD),
548 SYSCALL_WITH_NOCANCEL(read, FMT_FD_IO),
549 SYSCALL_WITH_NOCANCEL(write, FMT_FD_IO),
550 SYSCALL(fgetxattr, FMT_FD),
551 SYSCALL(fsetxattr, FMT_FD),
552 SYSCALL(fremovexattr, FMT_FD),
553 SYSCALL(flistxattr, FMT_FD),
554 SYSCALL(fstat, FMT_FD),
555 SYSCALL(fstat64, FMT_FD),
556 SYSCALL(fstat_extended, FMT_FD),
557 SYSCALL(fstat64_extended, FMT_FD),
558 NORMAL_SYSCALL(lstat),
559 NORMAL_SYSCALL(lstat64),
560 NORMAL_SYSCALL(lstat_extended),
561 SYSCALL_NAMED(lstat64_extended, lstat_extended64, FMT_DEFAULT),
562 NORMAL_SYSCALL(link),
563 NORMAL_SYSCALL(unlink),
564 NORMAL_SYSCALL(mknod),
565 SYSCALL(umask, FMT_UMASK),
566 SYSCALL(umask_extended, FMT_UMASK),
567 SYSCALL(chmod, FMT_CHMOD),
568 SYSCALL(chmod_extended, FMT_CHMOD_EXT),
569 SYSCALL(fchmod, FMT_FCHMOD),
570 SYSCALL(fchmod_extended, FMT_FCHMOD_EXT),
571 NORMAL_SYSCALL(chown),
572 NORMAL_SYSCALL(lchown),
573 SYSCALL(fchown, FMT_FD),
574 SYSCALL(access, FMT_ACCESS),
575 NORMAL_SYSCALL(access_extended),
576 NORMAL_SYSCALL(chdir),
577 NORMAL_SYSCALL(pthread_chdir),
578 NORMAL_SYSCALL(chroot),
579 NORMAL_SYSCALL(utimes),
580 SYSCALL_NAMED(delete, delete-Carbon, FMT_DEFAULT),
581 NORMAL_SYSCALL(undelete),
582 NORMAL_SYSCALL(revoke),
583 NORMAL_SYSCALL(fsctl),
584 SYSCALL(ffsctl, FMT_FD),
585 SYSCALL(chflags, FMT_CHFLAGS),
586 SYSCALL(fchflags, FMT_FCHFLAGS),
587 SYSCALL(fchdir, FMT_FD),
588 SYSCALL(pthread_fchdir, FMT_FD),
589 SYSCALL(futimes, FMT_FD),
590 NORMAL_SYSCALL(sync),
591 NORMAL_SYSCALL(symlink),
592 NORMAL_SYSCALL(readlink),
593 SYSCALL_WITH_NOCANCEL(fsync, FMT_FD),
594 SYSCALL(fdatasync, FMT_FD),
595 SYSCALL_WITH_NOCANCEL(readv, FMT_FD_IO),
596 SYSCALL_WITH_NOCANCEL(writev, FMT_FD_IO),
597 SYSCALL_WITH_NOCANCEL(pread, FMT_PREAD),
598 SYSCALL_WITH_NOCANCEL(pwrite, FMT_PREAD),
599 NORMAL_SYSCALL(mkdir),
600 NORMAL_SYSCALL(mkdir_extended),
601 NORMAL_SYSCALL(mkfifo),
602 NORMAL_SYSCALL(mkfifo_extended),
603 NORMAL_SYSCALL(rmdir),
604 NORMAL_SYSCALL(statfs),
605 NORMAL_SYSCALL(statfs64),
606 NORMAL_SYSCALL(getfsstat),
607 NORMAL_SYSCALL(getfsstat64),
608 SYSCALL(fstatfs, FMT_FD),
609 SYSCALL(fstatfs64, FMT_FD),
610 NORMAL_SYSCALL(pathconf),
611 SYSCALL(fpathconf, FMT_FD),
612 SYSCALL(getdirentries, FMT_FD_IO),
613 SYSCALL(getdirentries64, FMT_FD_IO),
614 SYSCALL(lseek, FMT_LSEEK),
615 SYSCALL(truncate, FMT_TRUNC),
616 SYSCALL(ftruncate, FMT_FTRUNC),
617 SYSCALL(flock, FMT_FLOCK),
618 NORMAL_SYSCALL(getattrlist),
619 NORMAL_SYSCALL(setattrlist),
620 SYSCALL(fgetattrlist, FMT_FD),
621 SYSCALL(fsetattrlist, FMT_FD),
622 SYSCALL(getdirentriesattr, FMT_FD),
623 NORMAL_SYSCALL(exchangedata),
624 NORMAL_SYSCALL(rename),
625 NORMAL_SYSCALL(copyfile),
626 NORMAL_SYSCALL(checkuseraccess),
627 NORMAL_SYSCALL(searchfs),
628 SYSCALL(aio_fsync, FMT_AIO_FSYNC),
629 SYSCALL(aio_return, FMT_AIO_RETURN),
630 SYSCALL_WITH_NOCANCEL(aio_suspend, FMT_AIO_SUSPEND),
631 SYSCALL(aio_cancel, FMT_AIO_CANCEL),
632 SYSCALL(aio_error, FMT_AIO),
633 SYSCALL(aio_read, FMT_AIO),
634 SYSCALL(aio_write, FMT_AIO),
635 SYSCALL(lio_listio, FMT_LIO_LISTIO),
636 SYSCALL_WITH_NOCANCEL(msync, FMT_MSYNC),
637 SYSCALL_WITH_NOCANCEL(fcntl, FMT_FCNTL),
638 SYSCALL(ioctl, FMT_IOCTL),
639 NORMAL_SYSCALL(fsgetpath),
640 NORMAL_SYSCALL(getattrlistbulk),
641 SYSCALL_WITH_NOCANCEL(openat, FMT_OPENAT), /* open_nocancel() was previously shown as "open_nocanel" (note spelling) */
642 SYSCALL(renameat, FMT_RENAMEAT),
643 SYSCALL(chmodat, FMT_CHMODAT),
644 SYSCALL(chownat, FMT_AT),
645 SYSCALL(fstatat, FMT_AT),
646 SYSCALL(fstatat64, FMT_AT),
647 SYSCALL(linkat, FMT_AT),
648 SYSCALL(unlinkat, FMT_AT),
649 SYSCALL(readlinkat, FMT_AT),
650 SYSCALL(symlinkat, FMT_AT),
651 SYSCALL(mkdirat, FMT_AT),
652 SYSCALL(getattrlistat, FMT_AT),
653};
8459d725 654
cf37c299
A
655static void
656get_screenwidth(void)
b51d5b5f 657{
cf37c299 658 struct winsize size;
b51d5b5f
A
659
660 columns = MAXCOLS;
661
cf37c299
A
662 if (isatty(STDOUT_FILENO)) {
663 if (ioctl(1, TIOCGWINSZ, &size) != -1) {
664 columns = size.ws_col;
09fd88e4
A
665
666 if (columns > MAXWIDTH)
cf37c299 667 columns = MAXWIDTH;
09fd88e4 668 }
b51d5b5f
A
669 }
670}
671
cf37c299
A
672static uint64_t
673mach_to_nano(uint64_t mach)
8459d725 674{
cf37c299
A
675 uint64_t nanoseconds = 0;
676 assert(ktrace_convert_timestamp_to_nanoseconds(s, mach, &nanoseconds) == 0);
8459d725 677
cf37c299 678 return nanoseconds;
8459d725
A
679}
680
cf37c299
A
681static void
682exit_usage(void)
683{
684 const char *myname;
8459d725 685
cf37c299 686 myname = getprogname();
1815bff5 687
fc6d9e4b 688 fprintf(stderr, "Usage: %s [-e] [-w] [-f mode] [-b] [-t seconds] [-R rawfile [-S start_time] [-E end_time]] [pid | cmd [pid | cmd] ...]\n", myname);
1c51fdde
A
689 fprintf(stderr, " -e exclude the specified list of pids from the sample\n");
690 fprintf(stderr, " and exclude fs_usage by default\n");
1815bff5 691 fprintf(stderr, " -w force wider, detailed, output\n");
fc6d9e4b
A
692 fprintf(stderr, " -f output is based on the mode provided\n");
693 fprintf(stderr, " mode = \"network\" Show network-related events\n");
694 fprintf(stderr, " mode = \"filesys\" Show filesystem-related events\n");
695 fprintf(stderr, " mode = \"pathname\" Show only pathname-related events\n");
696 fprintf(stderr, " mode = \"exec\" Show only exec and spawn events\n");
697 fprintf(stderr, " mode = \"diskio\" Show only disk I/O events\n");
698 fprintf(stderr, " mode = \"cachehit\" In addition, show cache hits\n");
699 fprintf(stderr, " -b annotate disk I/O events with BootCache info (if available)\n");
700 fprintf(stderr, " -t specifies timeout in seconds (for use in automated tools)\n");
8459d725
A
701 fprintf(stderr, " -R specifies a raw trace file to process\n");
702 fprintf(stderr, " -S if -R is specified, selects a start point in microseconds\n");
703 fprintf(stderr, " -E if -R is specified, selects an end point in microseconds\n");
1815bff5
A
704 fprintf(stderr, " pid selects process(s) to sample\n");
705 fprintf(stderr, " cmd selects process(s) matching command string to sample\n");
1c51fdde
A
706 fprintf(stderr, "By default (no options) the following processes are excluded from the output:\n");
707 fprintf(stderr, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");
1815bff5
A
708
709 exit(1);
710}
711
cf37c299
A
712int
713main(int argc, char *argv[])
714{
715 char ch;
716 int rv;
717 bool exclude_pids = false;
718 double time_limit = 0.0;
34d340d7 719
cf37c299 720 get_screenwidth();
34d340d7 721
cf37c299
A
722 s = ktrace_session_create();
723 assert(s);
34d340d7 724
cf37c299
A
725 while ((ch = getopt(argc, argv, "bewf:R:S:E:t:W")) != -1) {
726 switch (ch) {
727 case 'e':
728 exclude_pids = true;
729 break;
34d340d7 730
cf37c299
A
731 case 'w':
732 wideflag = 1;
733 columns = MAX_WIDE_MODE_COLS;
734 break;
34d340d7 735
cf37c299
A
736 case 'W':
737 include_waited_flag = true;
738 break;
34d340d7 739
cf37c299
A
740 case 'f':
741 if (!strcmp(optarg, "network"))
742 filter_mode |= NETWORK_FILTER;
743 else if (!strcmp(optarg, "filesys"))
744 filter_mode |= FILESYS_FILTER;
745 else if (!strcmp(optarg, "cachehit"))
746 show_cachehits = true;
747 else if (!strcmp(optarg, "exec"))
748 filter_mode |= EXEC_FILTER;
749 else if (!strcmp(optarg, "pathname"))
750 filter_mode |= PATHNAME_FILTER;
751 else if (!strcmp(optarg, "diskio"))
752 filter_mode |= DISKIO_FILTER;
34d340d7 753
cf37c299 754 break;
34d340d7 755
cf37c299
A
756 case 'b':
757 BC_flag = true;
758 break;
34d340d7 759
cf37c299
A
760 case 't':
761 time_limit = atof(optarg);
ef8ad44b 762
1a7e3f61 763 break;
cf37c299
A
764
765 case 'R':
766 RAW_flag = true;
767 rv = ktrace_set_file(s, optarg);
768 if (rv) {
769 fprintf(stderr, "ERROR: reading trace from '%s' failed (%s)\n", optarg, strerror(errno));
770 exit(1);
771 }
1a7e3f61 772 break;
cf37c299
A
773
774 case 'S':
775 start_time_ns = NSEC_PER_SEC * atof(optarg);
1a7e3f61 776 break;
cf37c299
A
777
778 case 'E':
779 end_time_ns = NSEC_PER_SEC * atof(optarg);
1a7e3f61 780 break;
cf37c299
A
781
782 default:
783 exit_usage();
34d340d7
A
784 }
785 }
786
cf37c299
A
787 argc -= optind;
788 argv += optind;
34d340d7 789
cf37c299
A
790 if (time_limit > 0.0) {
791 if (RAW_flag) {
792 fprintf(stderr, "NOTE: time limit ignored when a raw file is specified\n");
793 } else {
794 stop_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
795 dispatch_source_set_timer(stop_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * time_limit), DISPATCH_TIME_FOREVER, 0);
796 dispatch_source_set_event_handler(stop_timer, ^{
797 ktrace_end(s, 0);
798 });
799 dispatch_resume(stop_timer);
34d340d7 800 }
cf37c299 801 }
34d340d7 802
cf37c299
A
803 if (!RAW_flag) {
804 if (geteuid() != 0) {
805 fprintf(stderr, "'fs_usage' must be run as root...\n");
806 exit(1);
807 }
34d340d7 808
cf37c299
A
809 /*
810 * ktrace can't both *in*clude and *ex*clude pids, so: if we are
811 * already excluding pids, or if we are not explicitly including
812 * or excluding any pids, then exclude the defaults.
813 *
814 * if on the other hand we are explicitly including pids, we'll
815 * filter the defaults out naturally.
816 */
817 if (exclude_pids || argc == 0) {
818 ktrace_exclude_process(s, "fs_usage");
819 ktrace_exclude_process(s, "Terminal");
820 ktrace_exclude_process(s, "telnetd");
821 ktrace_exclude_process(s, "telnet");
822 ktrace_exclude_process(s, "sshd");
823 ktrace_exclude_process(s, "rlogind");
824 ktrace_exclude_process(s, "tcsh");
825 ktrace_exclude_process(s, "csh");
826 ktrace_exclude_process(s, "sh");
827 ktrace_exclude_process(s, "zsh");
828#if TARGET_OS_EMBEDDED
829 ktrace_exclude_process(s, "dropbear");
830#endif /* TARGET_OS_EMBEDDED */
831 }
832 }
34d340d7 833
cf37c299
A
834 /*
835 * If we're *in*cluding processes, also *in*clude the kernel_task, which
836 * issues trace points when disk I/Os complete. But set a flag for us to
837 * avoid showing events attributed to the kernel_task.
838 *
839 * If the user actually wants to those events, we'll change that flag in
840 * the loop below.
841 */
842 if (argc > 0 && !exclude_pids) {
843 ktrace_filter_pid(s, 0);
844 want_kernel_task = false;
845 }
34d340d7 846
cf37c299
A
847 /*
848 * Process the list of specified pids, and in/exclude them as
849 * appropriate.
850 */
851 while (argc > 0) {
852 pid_t pid;
853 char *name;
854 char *endptr;
34d340d7 855
cf37c299
A
856 name = argv[0];
857 pid = (pid_t)strtoul(name, &endptr, 10);
34d340d7 858
cf37c299
A
859 if (*name != '\0' && *endptr == '\0') {
860 if (exclude_pids) {
861 rv = ktrace_exclude_pid(s, pid);
862 } else {
863 if (pid == 0)
864 want_kernel_task = true;
865 else
866 rv = ktrace_filter_pid(s, pid);
867 }
868 } else {
869 if (exclude_pids) {
870 rv = ktrace_exclude_process(s, name);
871 } else {
872 if (!strcmp(name, "kernel_task"))
873 want_kernel_task = true;
874 else
875 rv = ktrace_filter_process(s, name);
876 }
877 }
34d340d7 878
cf37c299
A
879 if (rv == EINVAL) {
880 fprintf(stderr, "ERROR: cannot both include and exclude simultaneously\n");
881 exit(1);
882 } else {
883 assert(!rv);
884 }
34d340d7 885
cf37c299
A
886 argc--;
887 argv++;
888 }
34d340d7 889
cf37c299
A
890 /* provides SIGINT, SIGHUP, SIGPIPE, SIGTERM handlers */
891 ktrace_set_signal_handler(s);
34d340d7 892
cf37c299
A
893 ktrace_set_completion_handler(s, ^{
894 exit(0);
895 });
34d340d7 896
cf37c299
A
897 signal(SIGWINCH, SIG_IGN);
898 sigwinch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGWINCH, 0, dispatch_get_main_queue());
899 dispatch_source_set_event_handler(sigwinch_source, ^{
900 if (!wideflag)
901 get_screenwidth();
902 });
903 dispatch_resume(sigwinch_source);
34d340d7 904
cf37c299 905 init_shared_cache_mapping();
34d340d7 906
cf37c299 907 cache_disk_names();
34d340d7 908
cf37c299 909 setup_ktrace_callbacks();
34d340d7 910
cf37c299
A
911 ktrace_set_dropped_events_handler(s, ^{
912 fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly\n");
34d340d7 913
cf37c299 914 /* clear any state that is now potentially invalid */
34d340d7 915
cf37c299
A
916 event_delete_all();
917 fd_clear_all();
918 meta_delete_all();
919 });
34d340d7 920
cf37c299
A
921 ktrace_set_default_event_names_enabled(KTRACE_FEATURE_DISABLED);
922 ktrace_set_execnames_enabled(s, KTRACE_FEATURE_LAZY);
923 ktrace_set_vnode_paths_enabled(s, true);
34d340d7 924
cf37c299 925 rv = ktrace_start(s, dispatch_get_main_queue());
34d340d7 926
cf37c299
A
927 if (rv) {
928 perror("ktrace_start");
929 exit(1);
930 }
34d340d7 931
cf37c299 932 dispatch_main();
34d340d7 933
cf37c299
A
934 return 0;
935}
34d340d7 936
cf37c299
A
937void
938setup_ktrace_callbacks(void)
939{
940 ktrace_events_subclass(s, DBG_MACH, DBG_MACH_EXCP_SC, ^(ktrace_event_t event) {
941 int type;
34d340d7 942
cf37c299 943 type = event->debugid & KDBG_EVENTID_MASK;
34d340d7 944
cf37c299
A
945 if (type == MSC_map_fd) {
946 if (event->debugid & DBG_FUNC_START) {
947 event_enter(type, event);
948 } else {
949 event_exit("map_fd", type, event, FMT_FD);
950 }
951 }
952 });
34d340d7 953
cf37c299
A
954 ktrace_events_subclass(s, DBG_MACH, DBG_MACH_VM, ^(ktrace_event_t event) {
955 th_info_t ti;
956 unsigned int type;
34d340d7 957
cf37c299 958 type = event->debugid & KDBG_EVENTID_MASK;
34d340d7 959
cf37c299
A
960 if (type != MACH_pageout && type != MACH_vmfault)
961 return;
34d340d7 962
cf37c299
A
963 if (event->debugid & DBG_FUNC_START) {
964 event_enter(type, event);
965 } else {
966 switch (type) {
967 case MACH_pageout:
968 if (event->arg2)
969 event_exit("PAGE_OUT_ANON", type, event, FMT_PGOUT);
970 else
971 event_exit("PAGE_OUT_FILE", type, event, FMT_PGOUT);
972
973 break;
974
975 case MACH_vmfault:
976 if (event->arg4 == DBG_PAGEIN_FAULT)
977 event_exit("PAGE_IN", type, event, FMT_PGIN);
978 else if (event->arg4 == DBG_PAGEINV_FAULT)
979 event_exit("PAGE_IN_FILE", type, event, FMT_PGIN);
980 else if (event->arg4 == DBG_PAGEIND_FAULT)
981 event_exit("PAGE_IN_ANON", type, event, FMT_PGIN);
982 else if (event->arg4 == DBG_CACHE_HIT_FAULT)
983 event_exit("CACHE_HIT", type, event, FMT_CACHEHIT);
984 else if ((ti = event_find(event->threadid, type)))
985 event_delete(ti);
986
987 break;
988
989 default:
990 abort();
991 }
992 }
993 });
34d340d7 994
cf37c299
A
995 if (include_waited_flag || RAW_flag) {
996 ktrace_events_subclass(s, DBG_MACH, DBG_MACH_SCHED, ^(ktrace_event_t event) {
997 int type;
34d340d7 998
cf37c299 999 type = event->debugid & KDBG_EVENTID_MASK;
34d340d7 1000
cf37c299
A
1001 switch (type) {
1002 case MACH_idle:
1003 case MACH_sched:
1004 case MACH_stkhandoff:
1005 event_mark_thread_waited(event->threadid);
1006 }
1007 });
1008 }
34d340d7 1009
cf37c299
A
1010 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_FSRW, ^(ktrace_event_t event) {
1011 th_info_t ti;
1012 int type;
34d340d7 1013
cf37c299 1014 type = event->debugid & KDBG_EVENTID_MASK;
34d340d7 1015
cf37c299
A
1016 switch (type) {
1017 case HFS_modify_block_end:
1018 /*
1019 * the expected path here is as follows:
1020 * enter syscall
1021 * look up a path, which gets stored in ti->vnode / ti->pathname
1022 * modify a metadata block -- we assume the modification has something to do with the path that was looked up
1023 * leave syscall
1024 * ...
1025 * later, someone writes that metadata block; the last path associated with it is attributed
1026 */
1027 if ((ti = event_find(event->threadid, 0))) {
1028 if (ti->newest_pathname)
1029 meta_add_name(event->arg2, ti->newest_pathname);
1030 }
34d340d7 1031
cf37c299 1032 break;
34d340d7 1033
cf37c299
A
1034 case VFS_LOOKUP:
1035 if (event->debugid & DBG_FUNC_START) {
1036 if ((ti = event_find(event->threadid, 0)) && !ti->vnodeid) {
1037 ti->vnodeid = event->arg1;
1038 }
1039 }
34d340d7 1040
cf37c299 1041 /* it can be both start and end */
34d340d7 1042
cf37c299
A
1043 if (event->debugid & DBG_FUNC_END) {
1044 if ((ti = event_find(event->threadid, 0)) && ti->vnodeid) {
1045 const char *pathname;
34d340d7 1046
cf37c299 1047 pathname = ktrace_get_path_for_vp(s, ti->vnodeid);
34d340d7 1048
cf37c299 1049 ti->vnodeid = 0;
34d340d7 1050
cf37c299
A
1051 if (pathname) {
1052 if (ti->pathname[0] == '\0') {
1053 strncpy(ti->pathname, pathname, MAXPATHLEN);
1054 ti->newest_pathname = ti->pathname;
1055 } else if (ti->pathname2[0] == '\0') {
1056 strncpy(ti->pathname2, pathname, MAXPATHLEN);
1057 ti->newest_pathname = ti->pathname2;
1058 }
1059 }
1060 }
1061 }
34d340d7 1062
cf37c299
A
1063 break;
1064 }
34d340d7 1065
cf37c299
A
1066 if (type != Throttled && type != HFS_update)
1067 return;
34d340d7 1068
cf37c299
A
1069 if (event->debugid & DBG_FUNC_START) {
1070 event_enter(type, event);
1071 } else {
1072 switch (type) {
1073 case Throttled:
1074 event_exit(" THROTTLED", type, event, FMT_NOTHING);
1075 break;
34d340d7 1076
cf37c299
A
1077 case HFS_update:
1078 event_exit(" HFS_update", type, event, FMT_HFS_update);
1079 break;
34d340d7 1080
cf37c299
A
1081 default:
1082 abort();
1083 }
1084 }
1085 });
34d340d7 1086
cf37c299
A
1087 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_DKRW, ^(ktrace_event_t event) {
1088 struct diskio *dio;
1089 unsigned int type;
34d340d7 1090
cf37c299 1091 type = event->debugid & KDBG_EVENTID_MASK;
34d340d7 1092
cf37c299
A
1093 if ((type & P_DISKIO_MASK) == P_DISKIO) {
1094 diskio_start(type, event->arg1, event->arg2, event->arg3, event->arg4, event);
1095 } else if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
1096 if ((dio = diskio_complete(event->arg1, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
1097 dio->vnodeid = event->arg2;
1098 diskio_print(dio);
1099 diskio_free(dio);
1100 }
1101 }
1102 });
34d340d7 1103
cf37c299
A
1104 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_IOCTL, ^(ktrace_event_t event) {
1105 th_info_t ti;
1106 int type;
1107 pid_t pid;
34d340d7 1108
cf37c299 1109 type = event->debugid & KDBG_EVENTID_MASK;
34d340d7 1110
cf37c299
A
1111 switch (type) {
1112 case SPEC_unmap_info:
1113 pid = ktrace_get_pid_for_thread(s, event->threadid);
34d340d7 1114
cf37c299
A
1115 if (check_filter_mode(pid, NULL, SPEC_unmap_info, 0, 0, "SPEC_unmap_info"))
1116 format_print(NULL, " TrimExtent", event, type, FMT_UNMAP_INFO, event->timestamp, event->timestamp, 0, "", NULL);
34d340d7 1117
cf37c299 1118 break;
34d340d7 1119
cf37c299
A
1120 case SPEC_ioctl:
1121 if (event->debugid & DBG_FUNC_START) {
1122 event_enter(type, event);
1123 } else {
1124 if (event->arg2 == DKIOCSYNCHRONIZECACHE)
1125 event_exit("IOCTL", type, event, FMT_IOCTL_SYNCCACHE);
1126 else if (event->arg2 == DKIOCUNMAP)
1127 event_exit("IOCTL", type, event, FMT_IOCTL_UNMAP);
1128 else if (event->arg2 == DKIOCSYNCHRONIZE && (event->debugid & DBG_FUNC_ALL) == DBG_FUNC_NONE)
1129 event_exit("IOCTL", type, event, FMT_IOCTL_SYNC);
1130 else if ((ti = event_find(event->threadid, type)))
1131 event_delete(ti);
1132 }
34d340d7 1133
cf37c299
A
1134 break;
1135 }
1136 });
1137
1138 if (BC_flag || RAW_flag) {
1139 ktrace_events_subclass(s, DBG_FSYSTEM, DBG_BOOTCACHE, ^(ktrace_event_t event) {
1140 struct diskio *dio;
1141 unsigned int type;
1142
1143 type = event->debugid & KDBG_EVENTID_MASK;
1144
1145 switch (type) {
1146 case BC_IO_HIT:
1147 case BC_IO_HIT_STALLED:
1148 case BC_IO_MISS:
1149 case BC_IO_MISS_CUT_THROUGH:
1150 case BC_PLAYBACK_IO:
1151 if ((dio = diskio_find(event->arg1)) != NULL)
1152 dio->bc_info = type;
1153 }
1154 });
1155 }
34d340d7 1156
cf37c299
A
1157 void (^bsd_sc_proc_cb)(ktrace_event_t event) = ^(ktrace_event_t event) {
1158 int type, index;
1159 pid_t pid;
34d340d7 1160
cf37c299 1161 type = event->debugid & KDBG_EVENTID_MASK;
34d340d7 1162
cf37c299
A
1163 switch (type) {
1164 case BSC_exit: /* see below */
1165 return;
34d340d7 1166
cf37c299
A
1167 case proc_exit:
1168 event->arg1 = event->arg2 >> 8;
1169 type = BSC_exit;
34d340d7 1170
cf37c299
A
1171 pid = ktrace_get_pid_for_thread(s, event->threadid);
1172 fd_clear_pid(pid);
34d340d7 1173
cf37c299 1174 break;
34d340d7 1175
cf37c299
A
1176 case BSC_mmap:
1177 if (event->arg4 & MAP_ANON)
1178 return;
34d340d7 1179
cf37c299 1180 break;
34d340d7 1181 }
34d340d7 1182
cf37c299
A
1183 if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
1184 return;
34d340d7 1185
cf37c299
A
1186 if (!bsd_syscalls[index].sc_name)
1187 return;
34d340d7 1188
cf37c299
A
1189 if (event->debugid & DBG_FUNC_START) {
1190 event_enter(type, event);
1191 } else {
1192 event_exit(bsd_syscalls[index].sc_name, type, event, bsd_syscalls[index].sc_format);
1193 }
1194 };
1195
1196 ktrace_events_subclass(s, DBG_BSD, DBG_BSD_EXCP_SC, bsd_sc_proc_cb);
1197 ktrace_events_subclass(s, DBG_BSD, DBG_BSD_PROC, bsd_sc_proc_cb);
1198
1199 ktrace_events_range(s, KDBG_EVENTID(DBG_BSD, DBG_BSD_SC_EXTENDED_INFO, 0), KDBG_EVENTID(DBG_BSD, DBG_BSD_SC_EXTENDED_INFO2 + 1, 0), ^(ktrace_event_t event) {
1200 extend_syscall(event->threadid, event->debugid & KDBG_EVENTID_MASK, event);
1201 });
1202
1203 ktrace_events_subclass(s, DBG_CORESTORAGE, DBG_CS_IO, ^(ktrace_event_t event) {
1204 // the usual DBG_FUNC_START/END does not work for i/o since it will
1205 // return on a different thread, this code uses the P_CS_IO_Done (0x4) bit
1206 // instead. the trace command doesn't know how handle either method
1207 // (unmatched start/end or 0x4) but works a little better this way.
1208
1209 struct diskio *dio;
1210 int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
1211 bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
1212
1213 switch (cs_type) {
1214 case P_CS_ReadChunk:
1215 case P_CS_WriteChunk:
1216 case P_CS_MetaRead:
1217 case P_CS_MetaWrite:
1218 if (start) {
1219 diskio_start(cs_type, event->arg2, event->arg1, event->arg3, event->arg4, event);
1220 } else {
1221 if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
1222 diskio_print(dio);
1223 diskio_free(dio);
1224 }
1225 }
1815bff5 1226
cf37c299
A
1227 break;
1228 case P_CS_TransformRead:
1229 case P_CS_TransformWrite:
1230 case P_CS_MigrationRead:
1231 case P_CS_MigrationWrite:
1232 if (start) {
1233 diskio_start(cs_type, event->arg2, CS_DEV, event->arg3, event->arg4, event);
1234 } else {
1235 if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
1236 diskio_print(dio);
1237 diskio_free(dio);
1238 }
1239 }
fc6d9e4b 1240
cf37c299
A
1241 break;
1242 }
1243 });
1815bff5 1244
cf37c299
A
1245 ktrace_events_subclass(s, DBG_CORESTORAGE, 1 /* DBG_CS_SYNC */, ^(ktrace_event_t event) {
1246 int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
1247 bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
1248
1249 if (cs_type == P_CS_SYNC_DISK) {
1250 if (start) {
1251 event_enter(cs_type, event);
1252 } else {
1253 event_exit(" SyncCacheCS", cs_type, event, FMT_SYNC_DISK_CS);
1254 }
1255 }
1256 });
1257}
ef8ad44b 1258
cf37c299
A
1259/*
1260 * Handle system call extended trace data.
1261 * pread and pwrite:
1262 * Wipe out the kd args that were collected upon syscall_entry
1263 * because it is the extended info that we really want, and it
1264 * is all we really need.
1265 */
1266void
1267extend_syscall(uintptr_t thread, int type, ktrace_event_t event)
1268{
1269 th_info_t ti;
ef8ad44b 1270
cf37c299
A
1271 switch (type) {
1272 case BSC_mmap_extended:
1273 if ((ti = event_find(thread, BSC_mmap)) == NULL)
1274 return;
ef8ad44b 1275
cf37c299
A
1276 ti->arg8 = ti->arg3; /* save protection */
1277 ti->arg1 = event->arg1; /* the fd */
1278 ti->arg3 = event->arg2; /* bottom half address */
1279 ti->arg5 = event->arg3; /* bottom half size */
1280 break;
ef8ad44b 1281
cf37c299
A
1282 case BSC_mmap_extended2:
1283 if ((ti = event_find(thread, BSC_mmap)) == NULL)
1284 return;
9726c137 1285
cf37c299
A
1286 ti->arg2 = event->arg1; /* top half address */
1287 ti->arg4 = event->arg2; /* top half size */
1288 ti->arg6 = event->arg3; /* top half file offset */
1289 ti->arg7 = event->arg4; /* bottom half file offset */
fc6d9e4b
A
1290 break;
1291
cf37c299
A
1292 case BSC_msync_extended:
1293 if ((ti = event_find(thread, BSC_msync)) == NULL) {
1294 if ((ti = event_find(thread, BSC_msync_nocancel)) == NULL)
1295 return;
1296 }
1297
1298 ti->arg4 = event->arg1; /* top half address */
1299 ti->arg5 = event->arg2; /* top half size */
fc6d9e4b 1300 break;
ef8ad44b 1301
cf37c299
A
1302 case BSC_pread_extended:
1303 if ((ti = event_find(thread, BSC_pread)) == NULL) {
1304 if ((ti = event_find(thread, BSC_pread_nocancel)) == NULL)
1305 return;
1306 }
1815bff5 1307
cf37c299
A
1308 ti->arg1 = event->arg1; /* the fd */
1309 ti->arg2 = event->arg2; /* nbytes */
1310 ti->arg3 = event->arg3; /* top half offset */
1311 ti->arg4 = event->arg4; /* bottom half offset */
1312 break;
34d340d7 1313
cf37c299
A
1314 case BSC_pwrite_extended:
1315 if ((ti = event_find(thread, BSC_pwrite)) == NULL) {
1316 if ((ti = event_find(thread, BSC_pwrite_nocancel)) == NULL)
1317 return;
1318 }
1c51fdde 1319
cf37c299
A
1320 ti->arg1 = event->arg1; /* the fd */
1321 ti->arg2 = event->arg2; /* nbytes */
1322 ti->arg3 = event->arg3; /* top half offset */
1323 ti->arg4 = event->arg4; /* bottom half offset */
1324 break;
8459d725 1325 }
cf37c299 1326}
ef8ad44b 1327
cf37c299 1328#pragma mark printing routines
ef8ad44b 1329
cf37c299
A
1330static void
1331get_mode_nibble(char *buf, unsigned long smode, unsigned long special, char x_on, char x_off)
1332{
1333 if (smode & 04)
1334 buf[0] = 'r';
ef8ad44b 1335
cf37c299
A
1336 if (smode & 02)
1337 buf[1] = 'w';
8459d725 1338
cf37c299
A
1339 if (smode & 01) {
1340 if (special)
1341 buf[2] = x_on;
1342 else
1343 buf[2] = 'x';
1344 } else {
1345 if (special)
1346 buf[2] = x_off;
ef8ad44b 1347 }
cf37c299
A
1348}
1349
1350static void
1351get_mode_string(unsigned long mode, char *buf)
1352{
1353 memset(buf, '-', 9);
1354 buf[9] = '\0';
1815bff5 1355
cf37c299
A
1356 get_mode_nibble(&buf[6], mode, (mode & 01000), 't', 'T');
1357 get_mode_nibble(&buf[3], (mode>>3), (mode & 02000), 's', 'S');
1358 get_mode_nibble(&buf[0], (mode>>6), (mode & 04000), 's', 'S');
1359}
1815bff5 1360
cf37c299
A
1361static int
1362clip_64bit(char *s, uint64_t value)
1363{
1364 int clen = 0;
9726c137 1365
cf37c299
A
1366 if ( (value & 0xff00000000000000LL) )
1367 clen = printf("%s0x%16.16qx", s, value);
1368 else if ( (value & 0x00ff000000000000LL) )
1369 clen = printf("%s0x%14.14qx ", s, value);
1370 else if ( (value & 0x0000ff0000000000LL) )
1371 clen = printf("%s0x%12.12qx ", s, value);
1372 else if ( (value & 0x000000ff00000000LL) )
1373 clen = printf("%s0x%10.10qx ", s, value);
1374 else
1375 clen = printf("%s0x%8.8qx ", s, value);
9726c137 1376
cf37c299
A
1377 return clen;
1378}
34d340d7 1379
cf37c299
A
1380/*
1381 * ret = 1 means print the entry
1382 * ret = 0 means don't print the entry
1383 */
b51d5b5f 1384
cf37c299
A
1385/*
1386 * meaning of filter flags:
1387 * cachehit turn on display of CACHE_HIT events (which are filtered out by default)
1388 *
1389 * exec show exec/posix_spawn
1390 * pathname show events with a pathname and close()
1391 * diskio show disk I/Os
1392 * filesys show filesystem events
1393 * network show network events
1394 *
1395 * filters may be combined; default is all filters on (except cachehit)
1396 */
1397bool
1398check_filter_mode(pid_t pid, th_info_t ti, unsigned long type, int error, int retval, char *sc_name)
1399{
1400 bool ret = false;
1401 int network_fd_isset = 0;
1402 unsigned long fd;
1815bff5 1403
cf37c299
A
1404 /* cachehit is special -- it's not on by default */
1405 if (sc_name[0] == 'C' && !strcmp(sc_name, "CACHE_HIT")) {
1406 return show_cachehits;
1407 }
1815bff5 1408
cf37c299
A
1409 if (filter_mode == DEFAULT_DO_NOT_FILTER)
1410 return true;
fc6d9e4b 1411
cf37c299
A
1412 if (filter_mode & DISKIO_FILTER) {
1413 if ((type & P_DISKIO_MASK) == P_DISKIO)
1414 return true;
fc6d9e4b 1415
cf37c299
A
1416 if (type == Throttled)
1417 return true;
1418 }
8459d725 1419
cf37c299
A
1420 if (filter_mode & EXEC_FILTER) {
1421 if (type == BSC_execve || type == BSC_posix_spawn)
1422 return true;
ef8ad44b 1423 }
1815bff5 1424
cf37c299
A
1425 if (filter_mode & PATHNAME_FILTER) {
1426 if (ti && ti->pathname[0])
1427 return true;
1815bff5 1428
cf37c299
A
1429 if (type == BSC_close || type == BSC_close_nocancel ||
1430 type == BSC_guarded_close_np)
1431 return true;
1432 }
1815bff5 1433
cf37c299
A
1434 if (!ti) {
1435 if (filter_mode & FILESYS_FILTER)
1436 return true;
34d340d7 1437
cf37c299 1438 return 0;
1815bff5 1439 }
8459d725 1440
cf37c299
A
1441 switch (type) {
1442 case BSC_close:
1443 case BSC_close_nocancel:
1444 case BSC_guarded_close_np:
1445 fd = ti->arg1;
1446 network_fd_isset = fd_is_network(pid, fd);
1447
1448 if (error == 0)
1449 fd_set_is_network(pid, fd, false);
1450
1451 if (network_fd_isset) {
1452 if (filter_mode & NETWORK_FILTER)
1453 ret = true;
1454 } else {
1455 if (filter_mode & FILESYS_FILTER)
1456 ret = true;
1457 }
1815bff5 1458
cf37c299 1459 break;
1815bff5 1460
cf37c299
A
1461 case BSC_read:
1462 case BSC_write:
1463 case BSC_read_nocancel:
1464 case BSC_write_nocancel:
1465 /*
1466 * we don't care about error in these cases
1467 */
1468 fd = ti->arg1;
1815bff5 1469
cf37c299
A
1470 if (fd_is_network(pid, fd)) {
1471 if (filter_mode & NETWORK_FILTER)
1472 ret = true;
1473 } else if (filter_mode & FILESYS_FILTER) {
1474 ret = true;
1475 }
1815bff5 1476
cf37c299 1477 break;
1815bff5 1478
cf37c299
A
1479 case BSC_accept:
1480 case BSC_accept_nocancel:
1481 case BSC_socket:
1482 fd = retval;
1815bff5 1483
cf37c299
A
1484 if (error == 0)
1485 fd_set_is_network(pid, fd, true);
1815bff5 1486
cf37c299
A
1487 if (filter_mode & NETWORK_FILTER)
1488 ret = true;
1815bff5 1489
cf37c299 1490 break;
fc6d9e4b 1491
cf37c299
A
1492 case BSC_recvfrom:
1493 case BSC_sendto:
1494 case BSC_recvmsg:
1495 case BSC_sendmsg:
1496 case BSC_connect:
1497 case BSC_bind:
1498 case BSC_listen:
1499 case BSC_sendto_nocancel:
1500 case BSC_recvfrom_nocancel:
1501 case BSC_recvmsg_nocancel:
1502 case BSC_sendmsg_nocancel:
1503 case BSC_connect_nocancel:
1504 fd = ti->arg1;
1505
1506 if (error == 0)
1507 fd_set_is_network(pid, fd, true);
1508
1509 if (filter_mode & NETWORK_FILTER)
1510 ret = true;
fc6d9e4b 1511
cf37c299 1512 break;
fc6d9e4b 1513
cf37c299
A
1514 case BSC_select:
1515 case BSC_select_nocancel:
1516 case BSC_socketpair:
1517 /*
1518 * Cannot determine info about file descriptors
1519 */
1520 if (filter_mode & NETWORK_FILTER)
1521 ret = true;
9726c137 1522
cf37c299 1523 break;
fc6d9e4b 1524
cf37c299
A
1525 case BSC_dup:
1526 case BSC_dup2:
1527 /*
1528 * We track these cases for fd state only
1529 */
1530 fd = ti->arg1;
fc6d9e4b 1531
cf37c299
A
1532 if (error == 0 && fd_is_network(pid, fd)) {
1533 /*
1534 * then we are duping a socket descriptor
1535 */
1536 fd = retval; /* the new fd */
1537 fd_set_is_network(pid, fd, true);
1538 }
fc6d9e4b 1539
cf37c299 1540 break;
fc6d9e4b 1541
cf37c299
A
1542 default:
1543 if (filter_mode & FILESYS_FILTER)
1544 ret = true;
fc6d9e4b 1545
cf37c299 1546 break;
fc6d9e4b 1547 }
fc6d9e4b 1548
cf37c299 1549 return ret;
1815bff5
A
1550}
1551
cf37c299
A
1552/*
1553 * called from:
1554 *
1555 * exit_event() (syscalls etc.)
1556 * print_diskio() (disk I/Os)
1557 * block callback for TrimExtent
8459d725 1558 */
1815bff5 1559void
cf37c299
A
1560format_print(th_info_t ti, char *sc_name, ktrace_event_t event,
1561 unsigned long type, int format, uint64_t now, uint64_t stime,
1562 int waited, const char *pathname, struct diskio *dio)
1815bff5 1563{
cf37c299
A
1564 uint64_t secs, usecs;
1565 int nopadding = 0;
1566 static time_t last_walltime_secs = -1;
1567 const char *command_name;
1568 pid_t pid;
1569 int len = 0;
1570 int clen = 0;
1571 size_t tlen = 0;
1572 unsigned long class;
1573 uint64_t user_addr;
1574 uint64_t user_size;
1575 char *framework_name;
1576 char *framework_type;
1577 char *p1;
1578 char *p2;
1579 char buf[MAXWIDTH];
1580 char cs_diskname[32];
1581 unsigned long threadid;
1582 struct timeval now_walltime;
1815bff5 1583
cf37c299
A
1584 static char timestamp[32];
1585 static size_t timestamp_len = 0;
1815bff5 1586
cf37c299
A
1587 if (!mach_time_of_first_event)
1588 mach_time_of_first_event = now;
1815bff5 1589
cf37c299
A
1590 if (format == FMT_DISKIO || format == FMT_DISKIO_CS) {
1591 assert(dio);
1592 } else {
1593 assert(event);
1815bff5 1594
cf37c299
A
1595 if (format != FMT_UNMAP_INFO)
1596 assert(ti);
1597 }
1598
1599 /* <rdar://problem/19852325> Filter out WindowServer/xcpm ioctls in fs_usage */
1600 if (type == BSC_ioctl && ti->arg2 == 0xffffffffc030581dUL)
1601 return;
1815bff5 1602
cf37c299
A
1603 /* honor -S and -E */
1604 if (RAW_flag) {
1605 uint64_t relative_time_ns;
8459d725 1606
cf37c299 1607 relative_time_ns = mach_to_nano(now - mach_time_of_first_event);
8459d725 1608
cf37c299
A
1609 if (relative_time_ns < start_time_ns || relative_time_ns > end_time_ns)
1610 return;
8459d725 1611 }
1815bff5 1612
cf37c299 1613 class = KDBG_EXTRACT_CLASS(type);
1815bff5 1614
cf37c299
A
1615 if (dio) {
1616 command_name = dio->issuing_command;
1617 threadid = dio->issuing_thread;
1618 pid = dio->issuing_pid;
1619 now_walltime = dio->completed_walltime;
1620 } else {
1621 if (ti && ti->command[0] != '\0') {
1622 command_name = ti->command;
1623 threadid = ti->thread;
1624 pid = ti->pid;
1625 } else {
1626 command_name = ktrace_get_execname_for_thread(s, event->threadid);
1627 threadid = event->threadid;
1628 pid = ktrace_get_pid_for_thread(s, event->threadid);
1629 }
fc6d9e4b 1630
cf37c299
A
1631 now_walltime = event->walltime;
1632 }
1815bff5 1633
cf37c299
A
1634 if (!want_kernel_task && pid == 0)
1635 return;
8459d725 1636
cf37c299
A
1637 if (!command_name)
1638 command_name = "";
1639
1640 assert(now_walltime.tv_sec || now_walltime.tv_usec);
1641
1642 /* try and reuse the timestamp string */
1643 if (last_walltime_secs != now_walltime.tv_sec) {
1644 timestamp_len = strftime(timestamp, sizeof (timestamp), "%H:%M:%S", localtime(&now_walltime.tv_sec));
1645 last_walltime_secs = now_walltime.tv_sec;
1815bff5 1646 }
34d340d7 1647
cf37c299
A
1648 if (columns > MAXCOLS || wideflag) {
1649 tlen = timestamp_len;
1650 nopadding = 0;
1815bff5 1651
cf37c299
A
1652 sprintf(&timestamp[tlen], ".%06d", now_walltime.tv_usec);
1653 tlen += 7;
8459d725 1654
cf37c299 1655 timestamp[tlen] = '\0';
ef8ad44b 1656 } else {
cf37c299 1657 nopadding = 1;
1815bff5 1658 }
2fc1e207 1659
cf37c299 1660 clen = printf("%s %-17.17s", timestamp, sc_name);
1815bff5 1661
cf37c299 1662 framework_name = NULL;
2fc1e207 1663
cf37c299
A
1664 if (columns > MAXCOLS || wideflag) {
1665 off_t offset_reassembled = 0LL;
20e66415 1666
cf37c299
A
1667 switch (format) {
1668 case FMT_NOTHING:
1669 clen += printf(" ");
1670 break;
8459d725 1671
cf37c299
A
1672 case FMT_AT:
1673 case FMT_RENAMEAT:
1674 case FMT_DEFAULT:
1675 /*
1676 * pathname based system calls or
1677 * calls with no fd or pathname (i.e. sync)
1678 */
1679 if (event->arg1)
1680 clen += printf(" [%3d] ", (int)event->arg1);
1681 else
1682 clen += printf(" ");
aaff5f01 1683
cf37c299 1684 break;
fc6d9e4b 1685
cf37c299
A
1686 case FMT_FD:
1687 /*
1688 * fd based system call... no I/O
1689 */
1690 if (event->arg1)
1691 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1692 else
1693 clen += printf(" F=%-3d", (int)ti->arg1);
1815bff5 1694
cf37c299 1695 break;
34d340d7 1696
cf37c299
A
1697 case FMT_FD_2:
1698 /*
1699 * accept, dup, dup2
1700 */
1701 if (event->arg1)
1702 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1703 else
1704 clen += printf(" F=%-3d F=%-3d", (int)ti->arg1, (int)event->arg2);
34d340d7 1705
cf37c299 1706 break;
34d340d7 1707
cf37c299
A
1708 case FMT_FD_IO:
1709 /*
1710 * system calls with fd's that return an I/O completion count
1711 */
1712 if (event->arg1)
1713 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1714 else
1715 clen += printf(" F=%-3d B=0x%-6lx", (int)ti->arg1, event->arg2);
34d340d7 1716
cf37c299 1717 break;
34d340d7 1718
cf37c299
A
1719 case FMT_PGIN:
1720 /*
1721 * pagein
1722 */
1723 user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
34d340d7 1724
cf37c299
A
1725 lookup_name(user_addr, &framework_type, &framework_name);
1726 clen += clip_64bit(" A=", user_addr);
1727 break;
1815bff5 1728
cf37c299
A
1729 case FMT_CACHEHIT:
1730 /*
1731 * cache hit
1732 */
1733 user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
8459d725 1734
cf37c299
A
1735 lookup_name(user_addr, &framework_type, &framework_name);
1736 clen += clip_64bit(" A=", user_addr);
1737 break;
fc6d9e4b 1738
cf37c299
A
1739 case FMT_PGOUT:
1740 /*
1741 * pageout
1742 */
1743 clen += printf(" B=0x%-8lx", event->arg1);
1744 break;
8459d725 1745
cf37c299
A
1746 case FMT_HFS_update:
1747 {
1748 static const struct {
1749 int flag;
1750 char ch;
1751 } hfsflags[] = {
1752 { DBG_HFS_UPDATE_SKIPPED, 'S' },
1753 { DBG_HFS_UPDATE_FORCE, 'F' },
1754 { DBG_HFS_UPDATE_MODIFIED, 'M' },
1755 { DBG_HFS_UPDATE_MINOR, 'N' },
1756 { DBG_HFS_UPDATE_DATEADDED, 'd' },
1757 { DBG_HFS_UPDATE_CHGTIME, 'c' },
1758 { DBG_HFS_UPDATE_ACCTIME, 'a' },
1759 { DBG_HFS_UPDATE_MODTIME, 'm' },
1760 };
1761 size_t i;
1762 int flagcount;
1763 char *sbuf;
1764 int sflag = (int)event->arg2;
1765
1766 flagcount = sizeof (hfsflags) / sizeof (*hfsflags);
1767 sbuf = malloc(flagcount + 1);
1768
1769 for (i = 0; i < flagcount; i++) {
1770 if (sflag & hfsflags[i].flag) {
1771 sbuf[i] = hfsflags[i].ch;
1772 } else {
1773 sbuf[i] = '_';
1774 }
1775 }
8459d725 1776
cf37c299 1777 sbuf[flagcount] = '\0';
8459d725 1778
cf37c299 1779 clen += printf(" %*s(%s) ", 17 - flagcount, "", sbuf);
8459d725 1780
cf37c299 1781 free(sbuf);
b51d5b5f 1782
cf37c299 1783 pathname = ktrace_get_path_for_vp(s, event->arg1);
1815bff5 1784
cf37c299
A
1785 if (!pathname)
1786 pathname = "";
1815bff5 1787
cf37c299 1788 nopadding = 1;
b51d5b5f 1789
cf37c299 1790 break;
8459d725 1791 }
fc6d9e4b 1792
cf37c299 1793 case FMT_DISKIO:
8459d725 1794 /*
cf37c299 1795 * physical disk I/O
8459d725 1796 */
cf37c299
A
1797 if (dio->io_errno) {
1798 clen += printf(" D=0x%8.8lx [%3d]", dio->blkno, (int)dio->io_errno);
1799 } else {
1800 if (BC_flag)
1801 clen += printf(" D=0x%8.8lx B=0x%-6lx BC:%s /dev/%s ", dio->blkno, dio->iosize, BC_STR(dio->bc_info), find_disk_name(dio->dev));
1802 else
1803 clen += printf(" D=0x%8.8lx B=0x%-6lx /dev/%s ", dio->blkno, dio->iosize, find_disk_name(dio->dev));
1804
1805 if (dio->is_meta) {
1806 if (!(type & P_DISKIO_READ)) {
1807 pathname = meta_find_name(dio->blkno);
1808 }
1809 } else {
1810 pathname = ktrace_get_path_for_vp(s, dio->vnodeid);
1811
1812 if (!pathname)
1813 pathname = "";
1814 }
1815
1816 nopadding = 1;
1817 }
b51d5b5f 1818
cf37c299 1819 break;
b51d5b5f 1820
cf37c299
A
1821 case FMT_DISKIO_CS:
1822 /*
1823 * physical disk I/O
1824 */
1825 if (dio->io_errno)
1826 clen += printf(" D=0x%8.8lx [%3lu]", dio->blkno, dio->io_errno);
1827 else
1828 clen += printf(" D=0x%8.8lx B=0x%-6lx /dev/%s", dio->blkno, dio->iosize, generate_cs_disk_name(dio->dev, cs_diskname));
34d340d7 1829
cf37c299 1830 break;
b51d5b5f 1831
cf37c299
A
1832 case FMT_SYNC_DISK_CS:
1833 /*
1834 * physical disk sync cache
1835 */
1836 clen += printf(" /dev/%s", generate_cs_disk_name(event->arg1, cs_diskname));
34d340d7 1837
cf37c299 1838 break;
34d340d7 1839
cf37c299
A
1840 case FMT_MSYNC:
1841 {
1842 /*
1843 * msync
1844 */
1845 int mlen = 0;
34d340d7 1846
cf37c299 1847 buf[0] = '\0';
34d340d7 1848
cf37c299
A
1849 if (ti->arg3 & MS_ASYNC)
1850 mlen += sprintf(&buf[mlen], "MS_ASYNC | ");
1851 else
1852 mlen += sprintf(&buf[mlen], "MS_SYNC | ");
34d340d7 1853
cf37c299
A
1854 if (ti->arg3 & MS_INVALIDATE)
1855 mlen += sprintf(&buf[mlen], "MS_INVALIDATE | ");
1856 if (ti->arg3 & MS_KILLPAGES)
1857 mlen += sprintf(&buf[mlen], "MS_KILLPAGES | ");
1858 if (ti->arg3 & MS_DEACTIVATE)
1859 mlen += sprintf(&buf[mlen], "MS_DEACTIVATE | ");
1815bff5 1860
cf37c299
A
1861 if (ti->arg3 & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE | MS_KILLPAGES | MS_DEACTIVATE))
1862 mlen += sprintf(&buf[mlen], "UNKNOWN | ");
fc6d9e4b 1863
cf37c299
A
1864 if (mlen)
1865 buf[mlen - 3] = '\0';
34d340d7 1866
cf37c299
A
1867 if (event->arg1)
1868 clen += printf(" [%3d]", (int)event->arg1);
fc6d9e4b 1869
cf37c299
A
1870 user_addr = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg1);
1871 clen += clip_64bit(" A=", user_addr);
9726c137 1872
cf37c299 1873 user_size = (((off_t)(unsigned int)(ti->arg5)) << 32) | (unsigned int)(ti->arg2);
ef8ad44b 1874
cf37c299 1875 clen += printf(" B=0x%-16qx <%s>", user_size, buf);
8459d725 1876
cf37c299
A
1877 break;
1878 }
ef8ad44b 1879
cf37c299
A
1880 case FMT_FLOCK:
1881 {
1882 /*
1883 * flock
1884 */
1885 int mlen = 0;
34d340d7 1886
cf37c299 1887 buf[0] = '\0';
8459d725 1888
cf37c299
A
1889 if (ti->arg2 & LOCK_SH)
1890 mlen += sprintf(&buf[mlen], "LOCK_SH | ");
1891 if (ti->arg2 & LOCK_EX)
1892 mlen += sprintf(&buf[mlen], "LOCK_EX | ");
1893 if (ti->arg2 & LOCK_NB)
1894 mlen += sprintf(&buf[mlen], "LOCK_NB | ");
1895 if (ti->arg2 & LOCK_UN)
1896 mlen += sprintf(&buf[mlen], "LOCK_UN | ");
34d340d7 1897
cf37c299
A
1898 if (ti->arg2 & ~(LOCK_SH | LOCK_EX | LOCK_NB | LOCK_UN))
1899 mlen += sprintf(&buf[mlen], "UNKNOWN | ");
34d340d7 1900
cf37c299
A
1901 if (mlen)
1902 buf[mlen - 3] = '\0';
34d340d7 1903
cf37c299
A
1904 if (event->arg1)
1905 clen += printf(" F=%-3d[%3d] <%s>", (int)ti->arg1, (int)event->arg1, buf);
1906 else
1907 clen += printf(" F=%-3d <%s>", (int)ti->arg1, buf);
34d340d7 1908
cf37c299 1909 break;
34d340d7 1910 }
ef8ad44b 1911
cf37c299
A
1912 case FMT_FCNTL:
1913 {
1914 /*
1915 * fcntl
1916 */
1917 char *p = NULL;
1918 int fd = -1;
34d340d7 1919
cf37c299
A
1920 if (event->arg1)
1921 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
1922 else
1923 clen += printf(" F=%-3d", (int)ti->arg1);
1924
1925 switch(ti->arg2) {
1926 case F_DUPFD:
1927 p = "DUPFD";
1928 break;
1929
1930 case F_GETFD:
1931 p = "GETFD";
1932 break;
1933
1934 case F_SETFD:
1935 p = "SETFD";
1936 break;
1937
1938 case F_GETFL:
1939 p = "GETFL";
1940 break;
1941
1942 case F_SETFL:
1943 p = "SETFL";
1944 break;
1945
1946 case F_GETOWN:
1947 p = "GETOWN";
1948 break;
1949
1950 case F_SETOWN:
1951 p = "SETOWN";
1952 break;
1953
1954 case F_GETLK:
1955 p = "GETLK";
1956 break;
1957
1958 case F_SETLK:
1959 p = "SETLK";
1960 break;
1961
1962 case F_SETLKW:
1963 p = "SETLKW";
1964 break;
1965
1966 case F_PREALLOCATE:
1967 p = "PREALLOCATE";
1968 break;
1969
1970 case F_SETSIZE:
1971 p = "SETSIZE";
1972 break;
1973
1974 case F_RDADVISE:
1975 p = "RDADVISE";
1976 break;
1977
1978 case F_GETPATH:
1979 p = "GETPATH";
1980 break;
1981
1982 case F_FULLFSYNC:
1983 p = "FULLFSYNC";
1984 break;
1985
1986 case F_PATHPKG_CHECK:
1987 p = "PATHPKG_CHECK";
1988 break;
1989
1990 case F_OPENFROM:
1991 p = "OPENFROM";
1992
1993 if (event->arg1 == 0)
1994 fd = (int)event->arg2;
1995 break;
1996
1997 case F_UNLINKFROM:
1998 p = "UNLINKFROM";
1999 break;
2000
2001 case F_CHECK_OPENEVT:
2002 p = "CHECK_OPENEVT";
2003 break;
2004
2005 case F_NOCACHE:
2006 if (ti->arg3)
2007 p = "CACHING OFF";
2008 else
2009 p = "CACHING ON";
2010 break;
2011
2012 case F_GLOBAL_NOCACHE:
2013 if (ti->arg3)
2014 p = "CACHING OFF (GLOBAL)";
2015 else
2016 p = "CACHING ON (GLOBAL)";
2017 break;
34d340d7 2018
cf37c299 2019 }
34d340d7 2020
cf37c299
A
2021 if (p) {
2022 if (fd == -1)
2023 clen += printf(" <%s>", p);
2024 else
2025 clen += printf(" <%s> F=%d", p, fd);
2026 } else {
2027 clen += printf(" <CMD=%d>", (int)ti->arg2);
2028 }
34d340d7 2029
cf37c299
A
2030 break;
2031 }
34d340d7 2032
cf37c299
A
2033 case FMT_IOCTL:
2034 {
2035 /*
2036 * ioctl
2037 */
2038 if (event->arg1)
2039 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
2040 else
2041 clen += printf(" F=%-3d", (int)ti->arg1);
34d340d7 2042
cf37c299 2043 clen += printf(" <CMD=0x%x>", (int)ti->arg2);
ef8ad44b 2044
cf37c299
A
2045 break;
2046 }
34d340d7 2047
cf37c299
A
2048 case FMT_IOCTL_SYNC:
2049 {
2050 /*
2051 * ioctl
2052 */
2053 clen += printf(" <DKIOCSYNCHRONIZE> B=%lu /dev/%s", event->arg3, find_disk_name(event->arg1));
34d340d7 2054
cf37c299
A
2055 break;
2056 }
34d340d7 2057
cf37c299
A
2058 case FMT_IOCTL_SYNCCACHE:
2059 {
2060 /*
2061 * ioctl
2062 */
2063 clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(event->arg1));
34d340d7 2064
cf37c299
A
2065 break;
2066 }
fc6d9e4b 2067
cf37c299
A
2068 case FMT_IOCTL_UNMAP:
2069 {
2070 /*
2071 * ioctl
2072 */
2073 clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(event->arg1));
fc6d9e4b 2074
cf37c299 2075 break;
fc6d9e4b 2076 }
34d340d7 2077
cf37c299
A
2078 case FMT_UNMAP_INFO:
2079 {
2080 clen += printf(" D=0x%8.8lx B=0x%-6lx /dev/%s", event->arg2, event->arg3, find_disk_name(event->arg1));
8459d725 2081
cf37c299
A
2082 break;
2083 }
8459d725 2084
cf37c299
A
2085 case FMT_SELECT:
2086 /*
2087 * select
2088 */
2089 if (event->arg1)
2090 clen += printf(" [%3d]", (int)event->arg1);
2091 else
2092 clen += printf(" S=%-3d", (int)event->arg2);
8459d725 2093
cf37c299 2094 break;
34d340d7 2095
cf37c299
A
2096 case FMT_LSEEK:
2097 case FMT_PREAD:
2098 /*
2099 * pread, pwrite, lseek
2100 */
2101 clen += printf(" F=%-3d", (int)ti->arg1);
2102
2103 if (event->arg1) {
2104 clen += printf("[%3d] ", (int)event->arg1);
2105 } else {
2106 if (format == FMT_PREAD)
2107 clen += printf(" B=0x%-8lx ", event->arg2);
2108 else
2109 clen += printf(" ");
2110 }
34d340d7 2111
cf37c299
A
2112 if (format == FMT_PREAD)
2113 offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
2114 else
2115#ifdef __ppc__
2116 offset_reassembled = (((off_t)(unsigned int)(arg2)) << 32) | (unsigned int)(arg3);
2117#else
2118 offset_reassembled = (((off_t)(unsigned int)(event->arg3)) << 32) | (unsigned int)(event->arg2);
2119#endif
34d340d7 2120
cf37c299 2121 clen += clip_64bit("O=", offset_reassembled);
34d340d7 2122
cf37c299
A
2123 if (format == FMT_LSEEK) {
2124 char *mode;
34d340d7 2125
b58caf92 2126 if (ti->arg3 == SEEK_SET)
cf37c299 2127 mode = "SEEK_SET";
b58caf92 2128 else if (ti->arg3 == SEEK_CUR)
cf37c299 2129 mode = "SEEK_CUR";
b58caf92 2130 else if (ti->arg3 == SEEK_END)
cf37c299
A
2131 mode = "SEEK_END";
2132 else
2133 mode = "UNKNOWN";
34d340d7 2134
cf37c299
A
2135 clen += printf(" <%s>", mode);
2136 }
34d340d7 2137
cf37c299 2138 break;
34d340d7 2139
cf37c299
A
2140 case FMT_MMAP:
2141 /*
2142 * mmap
2143 */
2144 clen += printf(" F=%-3d ", (int)ti->arg1);
34d340d7 2145
cf37c299
A
2146 if (event->arg1) {
2147 clen += printf("[%3d] ", (int)event->arg1);
2148 } else {
2149 user_addr = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
34d340d7 2150
cf37c299 2151 clen += clip_64bit("A=", user_addr);
fc6d9e4b 2152
cf37c299 2153 offset_reassembled = (((off_t)(unsigned int)(ti->arg6)) << 32) | (unsigned int)(ti->arg7);
fc6d9e4b 2154
cf37c299 2155 clen += clip_64bit("O=", offset_reassembled);
34d340d7 2156
cf37c299 2157 user_size = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg5);
ef8ad44b 2158
cf37c299 2159 clen += printf("B=0x%-16qx", user_size);
34d340d7 2160
cf37c299 2161 clen += printf(" <");
34d340d7 2162
cf37c299
A
2163 if (ti->arg8 & PROT_READ)
2164 clen += printf("READ");
34d340d7 2165
cf37c299
A
2166 if (ti->arg8 & PROT_WRITE)
2167 clen += printf("|WRITE");
34d340d7 2168
cf37c299
A
2169 if (ti->arg8 & PROT_EXEC)
2170 clen += printf("|EXEC");
34d340d7 2171
cf37c299
A
2172 clen += printf(">");
2173 }
9726c137 2174
cf37c299 2175 break;
9726c137 2176
cf37c299
A
2177 case FMT_TRUNC:
2178 case FMT_FTRUNC:
2179 /*
2180 * ftruncate, truncate
2181 */
2182 if (format == FMT_FTRUNC)
2183 clen += printf(" F=%-3d", (int)ti->arg1);
2184 else
2185 clen += printf(" ");
aaff5f01 2186
cf37c299
A
2187 if (event->arg1)
2188 clen += printf("[%3d]", (int)event->arg1);
aaff5f01 2189
cf37c299
A
2190#ifdef __ppc__
2191 offset_reassembled = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
2192#else
2193 offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg2);
2194#endif
2195 clen += clip_64bit(" O=", offset_reassembled);
aaff5f01 2196
cf37c299
A
2197 nopadding = 1;
2198 break;
aaff5f01 2199
cf37c299
A
2200 case FMT_FCHFLAGS:
2201 case FMT_CHFLAGS:
2202 {
2203 /*
2204 * fchflags, chflags
2205 */
2206 int mlen = 0;
2207
2208 if (format == FMT_FCHFLAGS) {
2209 if (event->arg1)
2210 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
2211 else
2212 clen += printf(" F=%-3d", (int)ti->arg1);
2213 } else {
2214 if (event->arg1)
2215 clen += printf(" [%3d] ", (int)event->arg1);
2216 }
ef8ad44b 2217
cf37c299
A
2218 buf[mlen++] = ' ';
2219 buf[mlen++] = '<';
2220
2221 if (ti->arg2 & UF_NODUMP)
2222 mlen += sprintf(&buf[mlen], "UF_NODUMP | ");
2223 if (ti->arg2 & UF_IMMUTABLE)
2224 mlen += sprintf(&buf[mlen], "UF_IMMUTABLE | ");
2225 if (ti->arg2 & UF_APPEND)
2226 mlen += sprintf(&buf[mlen], "UF_APPEND | ");
2227 if (ti->arg2 & UF_OPAQUE)
2228 mlen += sprintf(&buf[mlen], "UF_OPAQUE | ");
2229 if (ti->arg2 & SF_ARCHIVED)
2230 mlen += sprintf(&buf[mlen], "SF_ARCHIVED | ");
2231 if (ti->arg2 & SF_IMMUTABLE)
2232 mlen += sprintf(&buf[mlen], "SF_IMMUTABLE | ");
2233 if (ti->arg2 & SF_APPEND)
2234 mlen += sprintf(&buf[mlen], "SF_APPEND | ");
2235
2236 if (ti->arg2 == 0)
2237 mlen += sprintf(&buf[mlen], "CLEAR_ALL_FLAGS | ");
2238 else if (ti->arg2 & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND))
2239 mlen += sprintf(&buf[mlen], "UNKNOWN | ");
2240
2241 if (mlen >= 3)
2242 mlen -= 3;
2243
2244 buf[mlen++] = '>';
2245 buf[mlen] = '\0';
2246
2247 if (mlen < 19) {
2248 memset(&buf[mlen], ' ', 19 - mlen);
2249 mlen = 19;
2250 buf[mlen] = '\0';
2251 }
ef8ad44b 2252
cf37c299 2253 clen += printf("%s", buf);
34d340d7 2254
cf37c299
A
2255 nopadding = 1;
2256 break;
2257 }
34d340d7 2258
cf37c299
A
2259 case FMT_UMASK:
2260 case FMT_FCHMOD:
2261 case FMT_FCHMOD_EXT:
2262 case FMT_CHMOD:
2263 case FMT_CHMOD_EXT:
2264 case FMT_CHMODAT:
2265 {
2266 /*
2267 * fchmod, fchmod_extended, chmod, chmod_extended
2268 */
2269 unsigned long mode;
2270
2271 if (format == FMT_FCHMOD || format == FMT_FCHMOD_EXT) {
2272 if (event->arg1)
2273 clen += printf(" F=%-3d[%3d] ", (int)ti->arg1, (int)event->arg1);
2274 else
2275 clen += printf(" F=%-3d ", (int)ti->arg1);
2276 } else {
2277 if (event->arg1)
2278 clen += printf(" [%3d] ", (int)event->arg1);
2279 else
2280 clen += printf(" ");
2281 }
34d340d7 2282
cf37c299
A
2283 if (format == FMT_UMASK)
2284 mode = ti->arg1;
2285 else if (format == FMT_FCHMOD || format == FMT_CHMOD || format == FMT_CHMODAT)
2286 mode = ti->arg2;
34d340d7 2287 else
cf37c299 2288 mode = ti->arg4;
34d340d7 2289
cf37c299 2290 get_mode_string(mode, &buf[0]);
34d340d7 2291
cf37c299
A
2292 if (event->arg1 == 0)
2293 clen += printf("<%s> ", buf);
34d340d7 2294 else
cf37c299
A
2295 clen += printf("<%s>", buf);
2296 break;
34d340d7 2297 }
34d340d7 2298
cf37c299
A
2299 case FMT_ACCESS:
2300 {
2301 /*
2302 * access
2303 */
2304 char mode[5];
2305
2306 memset(mode, '_', 4);
2307 mode[4] = '\0';
2308
2309 if (ti->arg2 & R_OK)
2310 mode[0] = 'R';
2311 if (ti->arg2 & W_OK)
2312 mode[1] = 'W';
2313 if (ti->arg2 & X_OK)
2314 mode[2] = 'X';
2315 if (ti->arg2 == F_OK)
2316 mode[3] = 'F';
2317
2318 if (event->arg1)
2319 clen += printf(" [%3d] (%s) ", (int)event->arg1, mode);
2320 else
2321 clen += printf(" (%s) ", mode);
34d340d7 2322
cf37c299
A
2323 nopadding = 1;
2324 break;
2325 }
34d340d7 2326
cf37c299
A
2327 case FMT_MOUNT:
2328 {
2329 if (event->arg1)
2330 clen += printf(" [%3d] <FLGS=0x%lx> ", (int)event->arg1, ti->arg3);
2331 else
2332 clen += printf(" <FLGS=0x%lx> ", ti->arg3);
34d340d7 2333
cf37c299
A
2334 nopadding = 1;
2335 break;
2336 }
34d340d7 2337
cf37c299
A
2338 case FMT_UNMOUNT:
2339 {
2340 char *mountflag;
34d340d7 2341
cf37c299
A
2342 if (ti->arg2 & MNT_FORCE)
2343 mountflag = "<FORCE>";
2344 else
2345 mountflag = "";
34d340d7 2346
cf37c299
A
2347 if (event->arg1)
2348 clen += printf(" [%3d] %s ", (int)event->arg1, mountflag);
2349 else
2350 clen += printf(" %s ", mountflag);
34d340d7 2351
cf37c299
A
2352 nopadding = 1;
2353 break;
34d340d7 2354 }
34d340d7 2355
cf37c299
A
2356 case FMT_OPENAT:
2357 case FMT_OPEN:
2358 {
2359 /*
2360 * open
2361 */
2362 char mode[7];
2363
2364 memset(mode, '_', 6);
2365 mode[6] = '\0';
2366
2367 if (ti->arg2 & O_RDWR) {
2368 mode[0] = 'R';
2369 mode[1] = 'W';
2370 } else if (ti->arg2 & O_WRONLY) {
2371 mode[1] = 'W';
2372 } else {
2373 mode[0] = 'R';
2374 }
34d340d7 2375
cf37c299
A
2376 if (ti->arg2 & O_CREAT)
2377 mode[2] = 'C';
34d340d7 2378
cf37c299
A
2379 if (ti->arg2 & O_APPEND)
2380 mode[3] = 'A';
34d340d7 2381
cf37c299
A
2382 if (ti->arg2 & O_TRUNC)
2383 mode[4] = 'T';
34d340d7 2384
cf37c299
A
2385 if (ti->arg2 & O_EXCL)
2386 mode[5] = 'E';
34d340d7 2387
cf37c299
A
2388 if (event->arg1)
2389 clen += printf(" [%3d] (%s) ", (int)event->arg1, mode);
34d340d7 2390 else
cf37c299 2391 clen += printf(" F=%-3d (%s) ", (int)event->arg2, mode);
34d340d7 2392
cf37c299
A
2393 nopadding = 1;
2394 break;
34d340d7 2395 }
34d340d7 2396
cf37c299
A
2397 case FMT_SOCKET:
2398 {
2399 /*
2400 * socket
2401 *
2402 */
2403 char *domain;
2404 char *type;
34d340d7 2405
cf37c299
A
2406 switch (ti->arg1) {
2407 case AF_UNIX:
2408 domain = "AF_UNIX";
2409 break;
34d340d7 2410
cf37c299
A
2411 case AF_INET:
2412 domain = "AF_INET";
2413 break;
34d340d7 2414
cf37c299
A
2415 case AF_ISO:
2416 domain = "AF_ISO";
2417 break;
34d340d7 2418
cf37c299
A
2419 case AF_NS:
2420 domain = "AF_NS";
2421 break;
34d340d7 2422
cf37c299
A
2423 case AF_IMPLINK:
2424 domain = "AF_IMPLINK";
2425 break;
34d340d7 2426
cf37c299
A
2427 default:
2428 domain = "UNKNOWN";
2429 break;
2430 }
34d340d7 2431
cf37c299
A
2432 switch (ti->arg2) {
2433 case SOCK_STREAM:
2434 type = "SOCK_STREAM";
2435 break;
2436 case SOCK_DGRAM:
2437 type = "SOCK_DGRAM";
2438 break;
2439 case SOCK_RAW:
2440 type = "SOCK_RAW";
2441 break;
2442 default:
2443 type = "UNKNOWN";
2444 break;
2445 }
34d340d7 2446
cf37c299
A
2447 if (event->arg1)
2448 clen += printf(" [%3d] <%s, %s, 0x%lx>", (int)event->arg1, domain, type, ti->arg3);
2449 else
2450 clen += printf(" F=%-3d <%s, %s, 0x%lx>", (int)event->arg2, domain, type, ti->arg3);
34d340d7 2451
cf37c299 2452 break;
34d340d7
A
2453 }
2454
cf37c299
A
2455 case FMT_AIO_FSYNC:
2456 {
2457 /*
2458 * aio_fsync [errno] AIOCBP OP
2459 */
2460 char *op;
34d340d7 2461
cf37c299
A
2462 if (ti->arg1 == O_SYNC || ti->arg1 == 0)
2463 op = "AIO_FSYNC";
2464#if O_DSYNC
2465 else if (ti->arg1 == O_DSYNC)
2466 op = "AIO_DSYNC";
2467#endif
2468 else
2469 op = "UNKNOWN";
34d340d7 2470
cf37c299
A
2471 if (event->arg1)
2472 clen += printf(" [%3d] P=0x%8.8lx <%s>", (int)event->arg1, ti->arg2, op);
2473 else
2474 clen += printf(" P=0x%8.8lx <%s>", ti->arg2, op);
34d340d7 2475
cf37c299 2476 break;
34d340d7
A
2477 }
2478
cf37c299
A
2479 case FMT_AIO_RETURN:
2480 /*
2481 * aio_return [errno] AIOCBP IOSIZE
2482 */
2483 if (event->arg1)
2484 clen += printf(" [%3d] P=0x%8.8lx", (int)event->arg1, ti->arg1);
2485 else
2486 clen += printf(" P=0x%8.8lx B=0x%-8lx", ti->arg1, event->arg2);
34d340d7 2487
cf37c299 2488 break;
34d340d7 2489
cf37c299
A
2490 case FMT_AIO_SUSPEND:
2491 /*
2492 * aio_suspend [errno] NENTS
2493 */
2494 if (event->arg1)
2495 clen += printf(" [%3d] N=%d", (int)event->arg1, (int)ti->arg2);
2496 else
2497 clen += printf(" N=%d", (int)ti->arg2);
34d340d7 2498
cf37c299 2499 break;
34d340d7 2500
cf37c299
A
2501 case FMT_AIO_CANCEL:
2502 /*
2503 * aio_cancel [errno] FD or AIOCBP (if non-null)
2504 */
2505 if (ti->arg2) {
2506 if (event->arg1)
2507 clen += printf(" [%3d] P=0x%8.8lx", (int)event->arg1, ti->arg2);
2508 else
2509 clen += printf(" P=0x%8.8lx", ti->arg2);
2510 } else {
2511 if (event->arg1)
2512 clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
2513 else
2514 clen += printf(" F=%-3d", (int)ti->arg1);
2515 }
34d340d7 2516
cf37c299 2517 break;
34d340d7 2518
cf37c299
A
2519 case FMT_AIO:
2520 /*
2521 * aio_error, aio_read, aio_write [errno] AIOCBP
2522 */
2523 if (event->arg1)
2524 clen += printf(" [%3d] P=0x%8.8lx", (int)event->arg1, ti->arg1);
34d340d7 2525 else
cf37c299 2526 clen += printf(" P=0x%8.8lx", ti->arg1);
34d340d7 2527
cf37c299 2528 break;
34d340d7 2529
cf37c299
A
2530 case FMT_LIO_LISTIO: {
2531 /*
2532 * lio_listio [errno] NENTS MODE
2533 */
2534 char *op;
34d340d7 2535
cf37c299
A
2536 if (ti->arg1 == LIO_NOWAIT)
2537 op = "LIO_NOWAIT";
2538 else if (ti->arg1 == LIO_WAIT)
2539 op = "LIO_WAIT";
2540 else
2541 op = "UNKNOWN";
34d340d7 2542
cf37c299
A
2543 if (event->arg1)
2544 clen += printf(" [%3d] N=%d <%s>", (int)event->arg1, (int)ti->arg3, op);
2545 else
2546 clen += printf(" N=%d <%s>", (int)ti->arg3, op);
34d340d7 2547
cf37c299
A
2548 break;
2549 }
34d340d7
A
2550 }
2551 }
2552
2553 /*
2554 * Calculate space available to print pathname
2555 */
2556 if (columns > MAXCOLS || wideflag)
cf37c299 2557 clen = columns - (clen + 14 + 20 + 11);
34d340d7 2558 else
cf37c299 2559 clen = columns - (clen + 14 + 12);
34d340d7 2560
cf37c299
A
2561 if (!nopadding)
2562 clen -= 3;
34d340d7 2563
cf37c299
A
2564 if (framework_name) {
2565 len = sprintf(&buf[0], " %s %s ", framework_type, framework_name);
2566 } else if (*pathname != '\0') {
1a7e3f61
A
2567 switch(format) {
2568 case FMT_AT:
2569 case FMT_OPENAT:
2570 case FMT_CHMODAT:
cf37c299 2571 len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg1, pathname);
1a7e3f61
A
2572 break;
2573 case FMT_RENAMEAT:
cf37c299 2574 len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg3, pathname);
1a7e3f61
A
2575 break;
2576 default:
2577 len = sprintf(&buf[0], " %s ", pathname);
2578 }
8459d725 2579
cf37c299 2580 if (format == FMT_MOUNT && ti->pathname2[0] != '\0') {
8459d725
A
2581 int len2;
2582
2583 memset(&buf[len], ' ', 2);
2584
cf37c299 2585 len2 = sprintf(&buf[len+2], " %s ", ti->pathname2);
8459d725
A
2586 len = len + 2 + len2;
2587 }
cf37c299
A
2588 } else {
2589 len = 0;
2590 }
34d340d7
A
2591
2592 if (clen > len) {
cf37c299 2593 /*
34d340d7
A
2594 * Add null padding if column length
2595 * is wider than the pathname length.
2596 */
cf37c299 2597 memset(&buf[len], ' ', clen - len);
34d340d7
A
2598 buf[clen] = '\0';
2599
2600 pathname = buf;
34d340d7 2601 } else if (clen == len) {
cf37c299 2602 pathname = buf;
34d340d7 2603 } else if ((clen > 0) && (clen < len)) {
cf37c299 2604 /*
34d340d7
A
2605 * This prints the tail end of the pathname
2606 */
cf37c299 2607 buf[len-clen] = ' ';
34d340d7
A
2608
2609 pathname = &buf[len - clen];
34d340d7 2610 } else {
cf37c299 2611 pathname = "";
34d340d7 2612 }
cf37c299 2613
34d340d7 2614 /*
cf37c299 2615 * fudge some additional system call overhead
34d340d7 2616 * that currently isn't tracked... this also
cf37c299 2617 * insures that we see a minimum of 1 us for
34d340d7
A
2618 * an elapsed time
2619 */
cf37c299
A
2620 usecs = (mach_to_nano(now - stime) + (NSEC_PER_USEC - 1)) / NSEC_PER_USEC;
2621 secs = usecs / USEC_PER_SEC;
2622 usecs -= secs * USEC_PER_SEC;
34d340d7 2623
cf37c299
A
2624 if (!nopadding)
2625 p1 = " ";
34d340d7 2626 else
cf37c299
A
2627 p1 = "";
2628
34d340d7 2629 if (waited)
cf37c299 2630 p2 = " W";
34d340d7 2631 else
cf37c299 2632 p2 = " ";
34d340d7
A
2633
2634 if (columns > MAXCOLS || wideflag)
cf37c299 2635 printf("%s%s %3llu.%06llu%s %s.%lu\n", p1, pathname, secs, usecs, p2, command_name, threadid);
34d340d7 2636 else
cf37c299
A
2637 printf("%s%s %3llu.%06llu%s %-12.12s\n", p1, pathname, secs, usecs, p2, command_name);
2638
2639 if (!RAW_flag)
2640 fflush(stdout);
1815bff5
A
2641}
2642
cf37c299
A
2643#pragma mark metadata info hash routines
2644
2645#define VN_HASH_SIZE 16384
2646#define VN_HASH_MASK (VN_HASH_SIZE - 1)
2647
2648typedef struct meta_info {
2649 struct meta_info *m_next;
2650 uint64_t m_blkno;
2651 char m_name[MAXPATHLEN];
2652} *meta_info_t;
2653
2654meta_info_t m_info_hash[VN_HASH_SIZE];
1815bff5 2655
fc6d9e4b 2656void
cf37c299
A
2657meta_add_name(uint64_t blockno, const char *pathname)
2658{
fc6d9e4b 2659 meta_info_t mi;
cf37c299 2660 int hashid;
fc6d9e4b
A
2661
2662 hashid = blockno & VN_HASH_MASK;
2663
2664 for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
2665 if (mi->m_blkno == blockno)
2666 break;
2667 }
cf37c299 2668
fc6d9e4b 2669 if (mi == NULL) {
cf37c299
A
2670 mi = malloc(sizeof (struct meta_info));
2671
fc6d9e4b
A
2672 mi->m_next = m_info_hash[hashid];
2673 m_info_hash[hashid] = mi;
2674 mi->m_blkno = blockno;
2675 }
cf37c299
A
2676
2677 strncpy(mi->m_name, pathname, sizeof (mi->m_name));
fc6d9e4b
A
2678}
2679
cf37c299
A
2680const char *
2681meta_find_name(uint64_t blockno)
2682{
fc6d9e4b
A
2683 meta_info_t mi;
2684 int hashid;
2685
2686 hashid = blockno & VN_HASH_MASK;
2687
2688 for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
2689 if (mi->m_blkno == blockno)
cf37c299 2690 return mi->m_name;
fc6d9e4b 2691 }
fc6d9e4b 2692
cf37c299 2693 return "";
fc6d9e4b
A
2694}
2695
cf37c299
A
2696void
2697meta_delete_all(void)
2698{
2699 meta_info_t mi, next;
2700 int i;
fc6d9e4b 2701
cf37c299
A
2702 for (i = 0; i < HASH_MASK; i++) {
2703 for (mi = m_info_hash[i]; mi; mi = next) {
2704 next = mi->m_next;
fc6d9e4b 2705
cf37c299
A
2706 free(mi);
2707 }
fc6d9e4b 2708
cf37c299 2709 m_info_hash[i] = NULL;
fc6d9e4b 2710 }
fc6d9e4b
A
2711}
2712
cf37c299 2713#pragma mark event ("thread info") routines
fc6d9e4b 2714
cf37c299
A
2715th_info_t th_info_hash[HASH_SIZE];
2716th_info_t th_info_freelist;
1815bff5 2717
cf37c299
A
2718static th_info_t
2719add_event(ktrace_event_t event, int type)
2720{
2721 th_info_t ti;
2722 int hashid;
2723 unsigned long eventid;
1815bff5 2724
8459d725
A
2725 if ((ti = th_info_freelist))
2726 th_info_freelist = ti->next;
2727 else
cf37c299 2728 ti = malloc(sizeof (struct th_info));
8459d725 2729
cf37c299
A
2730 bzero(ti, sizeof (struct th_info));
2731
2732 hashid = event->threadid & HASH_MASK;
8459d725
A
2733
2734 ti->next = th_info_hash[hashid];
2735 th_info_hash[hashid] = ti;
2736
cf37c299
A
2737 eventid = event->debugid & KDBG_EVENTID_MASK;
2738
2739 if (eventid == BSC_execve || eventid == BSC_posix_spawn) {
2740 const char *command;
2741
2742 command = ktrace_get_execname_for_thread(s, event->threadid);
8459d725 2743
cf37c299
A
2744 if (!command)
2745 command = "";
fc6d9e4b 2746
cf37c299
A
2747 strncpy(ti->command, command, sizeof (ti->command));
2748 ti->command[MAXCOMLEN] = '\0';
2749 }
fc6d9e4b 2750
cf37c299
A
2751 ti->thread = event->threadid;
2752 ti->type = type;
8459d725 2753
cf37c299 2754 return ti;
1815bff5
A
2755}
2756
8459d725 2757th_info_t
cf37c299
A
2758event_find(uintptr_t thread, int type)
2759{
2760 th_info_t ti;
2761 int hashid;
1815bff5 2762
8459d725 2763 hashid = thread & HASH_MASK;
1815bff5 2764
8459d725
A
2765 for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
2766 if (ti->thread == thread) {
cf37c299
A
2767 if (type == ti->type)
2768 return ti;
2769
8459d725 2770 if (type == 0)
cf37c299 2771 return ti;
8459d725
A
2772 }
2773 }
1815bff5 2774
cf37c299 2775 return NULL;
8459d725
A
2776}
2777
8459d725 2778void
cf37c299 2779event_delete(th_info_t ti_to_delete)
1815bff5 2780{
cf37c299
A
2781 th_info_t ti;
2782 th_info_t ti_prev;
2783 int hashid;
ef8ad44b 2784
cf37c299 2785 hashid = ti_to_delete->thread & HASH_MASK;
8459d725 2786
cf37c299
A
2787 if ((ti = th_info_hash[hashid])) {
2788 if (ti == ti_to_delete)
2789 th_info_hash[hashid] = ti->next;
2790 else {
2791 ti_prev = ti;
8459d725 2792
cf37c299
A
2793 for (ti = ti->next; ti; ti = ti->next) {
2794 if (ti == ti_to_delete) {
2795 ti_prev->next = ti->next;
2796 break;
8459d725 2797 }
cf37c299 2798 ti_prev = ti;
8459d725
A
2799 }
2800 }
cf37c299
A
2801 if (ti) {
2802 ti->next = th_info_freelist;
2803 th_info_freelist = ti;
8459d725 2804 }
cf37c299
A
2805 }
2806}
2807
2808void
2809event_delete_all(void)
2810{
2811 th_info_t ti = 0;
2812 th_info_t ti_next = 0;
2813 int i;
8459d725 2814
cf37c299 2815 for (i = 0; i < HASH_SIZE; i++) {
8459d725 2816
cf37c299
A
2817 for (ti = th_info_hash[i]; ti; ti = ti_next) {
2818 ti_next = ti->next;
2819 ti->next = th_info_freelist;
2820 th_info_freelist = ti;
8459d725 2821 }
cf37c299
A
2822 th_info_hash[i] = 0;
2823 }
2824}
8459d725 2825
cf37c299
A
2826void
2827event_enter(int type, ktrace_event_t event)
2828{
2829 th_info_t ti;
8459d725 2830
cf37c299
A
2831#if DEBUG
2832 int index;
2833 bool found;
8459d725 2834
cf37c299 2835 found = false;
8459d725 2836
cf37c299
A
2837 switch (type) {
2838 case P_CS_SYNC_DISK:
2839 case MACH_pageout:
2840 case MACH_vmfault:
2841 case MSC_map_fd:
2842 case SPEC_ioctl:
2843 case Throttled:
2844 case HFS_update:
2845 found = true;
20e66415 2846 }
20e66415 2847
cf37c299
A
2848 if ((type & CSC_MASK) == BSC_BASE) {
2849 if ((index = BSC_INDEX(type)) < MAX_BSD_SYSCALL && bsd_syscalls[index].sc_name)
2850 found = true;
2851 }
8459d725 2852
cf37c299
A
2853 assert(found);
2854#endif /* DEBUG */
8459d725 2855
cf37c299
A
2856 if ((ti = add_event(event, type)) == NULL)
2857 return;
8459d725 2858
cf37c299
A
2859 ti->stime = event->timestamp;
2860 ti->arg1 = event->arg1;
2861 ti->arg2 = event->arg2;
2862 ti->arg3 = event->arg3;
2863 ti->arg4 = event->arg4;
1815bff5
A
2864}
2865
cf37c299
A
2866void
2867event_exit(char *sc_name, int type, ktrace_event_t event, int format)
1815bff5 2868{
cf37c299
A
2869 th_info_t ti;
2870 pid_t pid;
2871
2872 if ((ti = event_find(event->threadid, type)) == NULL)
2873 return;
8459d725 2874
cf37c299 2875 pid = ktrace_get_pid_for_thread(s, event->threadid);
8459d725 2876
cf37c299
A
2877 if (check_filter_mode(pid, ti, type, (int)event->arg1, (int)event->arg2, sc_name)) {
2878 const char *pathname;
8459d725 2879
cf37c299 2880 pathname = NULL;
8459d725 2881
cf37c299
A
2882 /* most things are just interested in the first lookup */
2883 if (ti->pathname[0] != '\0')
2884 pathname = ti->pathname;
8459d725 2885
cf37c299
A
2886 if (!pathname)
2887 pathname = "";
8459d725 2888
cf37c299 2889 format_print(ti, sc_name, event, type, format, event->timestamp, ti->stime, ti->waited, pathname, NULL);
20e66415 2890 }
8459d725 2891
cf37c299
A
2892 event_delete(ti);
2893}
8459d725 2894
cf37c299
A
2895void
2896event_mark_thread_waited(uintptr_t thread)
8459d725 2897{
cf37c299
A
2898 th_info_t ti;
2899 int hashid;
20e66415 2900
8459d725
A
2901 hashid = thread & HASH_MASK;
2902
cf37c299
A
2903 for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
2904 if (ti->thread == thread)
2905 ti->waited = 1;
8459d725 2906 }
1815bff5
A
2907}
2908
cf37c299 2909#pragma mark network fd set routines
1815bff5 2910
cf37c299
A
2911struct pid_fd_set {
2912 struct pid_fd_set *next;
2913 pid_t pid;
2914 char *set;
2915 size_t setsize; /* number of *bytes*, not bits */
2916};
2917
2918struct pid_fd_set *pfs_hash[HASH_SIZE];
2919
2920static struct pid_fd_set *
2921pfs_get(pid_t pid)
1815bff5 2922{
cf37c299
A
2923 struct pid_fd_set *pfs;
2924 int hashid;
8459d725 2925
cf37c299
A
2926 assert(pid >= 0);
2927
2928 hashid = pid & HASH_MASK;
2929
2930 for (pfs = pfs_hash[hashid]; pfs; pfs = pfs->next) {
2931 if (pfs->pid == pid) {
2932 return pfs;
8459d725 2933 }
1815bff5 2934 }
1815bff5 2935
cf37c299
A
2936 pfs = calloc(1, sizeof (struct pid_fd_set));
2937
2938 pfs->pid = pid;
2939 pfs->set = NULL;
2940 pfs->setsize = 0;
2941 pfs->next = pfs_hash[hashid];
2942 pfs_hash[hashid] = pfs;
2943
2944 return pfs;
2945}
8459d725
A
2946
2947void
cf37c299 2948fd_clear_pid(pid_t pid)
20e66415 2949{
cf37c299
A
2950 struct pid_fd_set *pfs, *prev;
2951 int hashid;
8459d725 2952
cf37c299 2953 if (pid < 0)
8459d725 2954 return;
8459d725 2955
cf37c299 2956 hashid = pid & HASH_MASK;
8459d725 2957
cf37c299
A
2958 pfs = pfs_hash[hashid];
2959 prev = NULL;
20e66415 2960
cf37c299
A
2961 while (pfs) {
2962 if (pfs->pid == pid) {
2963 if (prev) {
2964 prev->next = pfs->next;
2965 } else {
2966 pfs_hash[hashid] = pfs->next;
2967 }
1815bff5 2968
cf37c299
A
2969 free(pfs->set);
2970 free(pfs);
8459d725 2971
cf37c299
A
2972 break;
2973 } else {
2974 prev = pfs;
2975 pfs = pfs->next;
2976 }
8459d725 2977 }
8459d725 2978}
8459d725 2979
1815bff5 2980void
cf37c299 2981fd_clear_all(void)
1815bff5 2982{
cf37c299
A
2983 struct pid_fd_set *pfs, *next;
2984 int i;
8459d725 2985
cf37c299
A
2986 for (i = 0; i < HASH_SIZE; i++) {
2987 for (pfs = pfs_hash[i]; pfs; pfs = next) {
2988 next = pfs->next;
1815bff5 2989
cf37c299
A
2990 free(pfs->set);
2991 free(pfs);
2992 }
8459d725 2993
cf37c299
A
2994 pfs_hash[i] = NULL;
2995 }
2996}
8459d725 2997
1815bff5 2998void
cf37c299 2999fd_set_is_network(pid_t pid, unsigned long fd, bool set)
1815bff5 3000{
cf37c299 3001 struct pid_fd_set *pfs;
1815bff5 3002
cf37c299
A
3003 if (pid < 0)
3004 return;
8459d725 3005
cf37c299 3006 pfs = pfs_get(pid);
1815bff5 3007
cf37c299
A
3008 if (fd >= pfs->setsize * CHAR_BIT) {
3009 size_t newsize;
1815bff5 3010
cf37c299 3011 if (!set) return;
1815bff5 3012
cf37c299
A
3013 newsize = MAX((fd + CHAR_BIT) / CHAR_BIT, 2 * pfs->setsize);
3014 pfs->set = reallocf(pfs->set, newsize);
3015 assert(pfs->set);
b51d5b5f 3016
cf37c299
A
3017 bzero(pfs->set + pfs->setsize, newsize - pfs->setsize);
3018 pfs->setsize = newsize;
3019 }
34d340d7 3020
cf37c299
A
3021 if (set)
3022 setbit(pfs->set, fd);
3023 else
3024 clrbit(pfs->set, fd);
3025}
34d340d7 3026
cf37c299
A
3027bool
3028fd_is_network(pid_t pid, unsigned long fd)
3029{
3030 struct pid_fd_set *pfs;
ef8ad44b 3031
cf37c299
A
3032 if (pid < 0)
3033 return false;
3034
3035 pfs = pfs_get(pid);
3036
3037 if (fd >= pfs->setsize * CHAR_BIT) {
3038 return false;
b51d5b5f 3039 }
cf37c299
A
3040
3041 return isset(pfs->set, fd);
b51d5b5f
A
3042}
3043
cf37c299
A
3044#pragma mark shared region address lookup routines
3045
3046#define MAXINDEX 2048
3047
3048struct library_range {
3049 uint64_t b_address;
3050 uint64_t e_address;
3051};
3052
3053struct library_info {
3054 uint64_t b_address;
3055 uint64_t e_address;
3056 int r_type;
3057 char *name;
3058};
3059
3060struct library_range framework32 = {0, 0};
3061struct library_range framework64 = {0, 0};
3062struct library_range framework64h = {0, 0};
b51d5b5f 3063
cf37c299
A
3064struct library_info library_infos[MAXINDEX];
3065int num_libraries = 0;
b51d5b5f 3066
cf37c299
A
3067#define TEXT_R 0
3068#define DATA_R 1
3069#define OBJC_R 2
3070#define IMPORT_R 3
3071#define UNICODE_R 4
3072#define IMAGE_R 5
3073#define LINKEDIT_R 6
b51d5b5f 3074
cf37c299
A
3075static void
3076sort_library_addresses(void)
3077{
3078 library_infos[num_libraries].b_address = library_infos[num_libraries - 1].b_address + 0x800000;
3079 library_infos[num_libraries].e_address = library_infos[num_libraries].b_address;
3080 library_infos[num_libraries].name = NULL;
3081
3082 qsort_b(library_infos, num_libraries, sizeof (struct library_info), ^int(const void *aa, const void *bb) {
3083 struct library_info *a = (struct library_info *)aa;
3084 struct library_info *b = (struct library_info *)bb;
3085
3086 if (a->b_address < b->b_address) return -1;
3087 if (a->b_address == b->b_address) return 0;
3088 return 1;
3089 });
3090}
b51d5b5f 3091
cf37c299
A
3092static int
3093scanline(char *inputstring, char **argv, int maxtokens)
b51d5b5f 3094{
8459d725
A
3095 int n = 0;
3096 char **ap = argv, *p, *val;
3097
3098 for (p = inputstring; n < maxtokens && p != NULL; ) {
cf37c299 3099 while ((val = strsep(&p, " \t")) != NULL && *val == '\0') ;
8459d725
A
3100
3101 *ap++ = val;
3102 n++;
3103 }
cf37c299 3104
8459d725
A
3105 *ap = 0;
3106
3107 return n;
b51d5b5f
A
3108}
3109
cf37c299
A
3110static int
3111read_shared_cache_map(const char *path, struct library_range *lr, char *linkedit_name)
b51d5b5f 3112{
ef8ad44b
A
3113 uint64_t b_address, e_address;
3114 char buf[1024];
cf37c299 3115 char *fnp, *fn_tofree;
ef8ad44b
A
3116 FILE *fd;
3117 char frameworkName[256];
3118 char *tokens[64];
3119 int ntokens;
3120 int type;
3121 int linkedit_found = 0;
3122 char *substring, *ptr;
b51d5b5f 3123
34d340d7
A
3124 bzero(buf, sizeof(buf));
3125 bzero(tokens, sizeof(tokens));
3126
3127 lr->b_address = 0;
3128 lr->e_address = 0;
b51d5b5f 3129
34d340d7 3130 if ((fd = fopen(path, "r")) == 0)
34d340d7 3131 return 0;
8459d725 3132
34d340d7
A
3133 while (fgets(buf, 1023, fd)) {
3134 if (strncmp(buf, "mapping", 7))
3135 break;
3136 }
cf37c299 3137
34d340d7 3138 buf[strlen(buf)-1] = 0;
cf37c299 3139
34d340d7 3140 frameworkName[0] = 0;
b51d5b5f 3141
34d340d7 3142 for (;;) {
34d340d7
A
3143 /*
3144 * Extract lib name from path name
b51d5b5f 3145 */
cf37c299 3146 if ((substring = strrchr(buf, '.'))) {
34d340d7 3147 /*
cf37c299 3148 * There is a ".": name is whatever is between the "/" around the "."
34d340d7 3149 */
8459d725 3150 while ( *substring != '/') /* find "/" before "." */
34d340d7 3151 substring--;
cf37c299 3152
34d340d7 3153 substring++;
8459d725 3154
34d340d7
A
3155 strncpy(frameworkName, substring, 256); /* copy path from "/" */
3156 frameworkName[255] = 0;
3157 substring = frameworkName;
3158
3159 while ( *substring != '/' && *substring) /* find "/" after "." and stop string there */
3160 substring++;
cf37c299 3161
34d340d7 3162 *substring = 0;
cf37c299 3163 } else {
34d340d7
A
3164 /*
3165 * No ".": take segment after last "/"
3166 */
3167 ptr = buf;
3168 substring = ptr;
3169
8459d725 3170 while (*ptr) {
34d340d7
A
3171 if (*ptr == '/')
3172 substring = ptr + 1;
3173 ptr++;
3174 }
cf37c299 3175
34d340d7
A
3176 strncpy(frameworkName, substring, 256);
3177 frameworkName[255] = 0;
3178 }
cf37c299
A
3179
3180 fnp = malloc(strlen(frameworkName) + 1);
3181 fn_tofree = fnp;
ef8ad44b
A
3182 strcpy(fnp, frameworkName);
3183
cf37c299 3184 while (fgets(buf, 1023, fd) && num_libraries < (MAXINDEX - 2)) {
34d340d7
A
3185 /*
3186 * Get rid of EOL
3187 */
3188 buf[strlen(buf)-1] = 0;
b51d5b5f 3189
34d340d7 3190 ntokens = scanline(buf, tokens, 64);
b51d5b5f 3191
34d340d7
A
3192 if (ntokens < 4)
3193 continue;
b51d5b5f 3194
ef8ad44b
A
3195 if (strncmp(tokens[0], "__TEXT", 6) == 0)
3196 type = TEXT_R;
3197 else if (strncmp(tokens[0], "__DATA", 6) == 0)
3198 type = DATA_R;
3199 else if (strncmp(tokens[0], "__OBJC", 6) == 0)
3200 type = OBJC_R;
3201 else if (strncmp(tokens[0], "__IMPORT", 8) == 0)
3202 type = IMPORT_R;
3203 else if (strncmp(tokens[0], "__UNICODE", 9) == 0)
3204 type = UNICODE_R;
3205 else if (strncmp(tokens[0], "__IMAGE", 7) == 0)
3206 type = IMAGE_R;
3207 else if (strncmp(tokens[0], "__LINKEDIT", 10) == 0)
3208 type = LINKEDIT_R;
3209 else
3210 type = -1;
b51d5b5f 3211
ef8ad44b
A
3212 if (type == LINKEDIT_R && linkedit_found)
3213 break;
b51d5b5f 3214
ef8ad44b
A
3215 if (type != -1) {
3216 b_address = strtoull(tokens[1], 0, 16);
3217 e_address = strtoull(tokens[3], 0, 16);
b51d5b5f 3218
cf37c299
A
3219 library_infos[num_libraries].b_address = b_address;
3220 library_infos[num_libraries].e_address = e_address;
3221 library_infos[num_libraries].r_type = type;
3222
ef8ad44b 3223 if (type == LINKEDIT_R) {
cf37c299 3224 library_infos[num_libraries].name = linkedit_name;
ef8ad44b 3225 linkedit_found = 1;
cf37c299
A
3226 } else {
3227 library_infos[num_libraries].name = fnp;
3228 fn_tofree = NULL;
3229 }
34d340d7 3230#if 0
ef8ad44b 3231 printf("%s(%d): %qx-%qx\n", frameworkInfo[numFrameworks].name, type, b_address, e_address);
34d340d7 3232#endif
ef8ad44b
A
3233 if (lr->b_address == 0 || b_address < lr->b_address)
3234 lr->b_address = b_address;
b51d5b5f 3235
ef8ad44b
A
3236 if (lr->e_address == 0 || e_address > lr->e_address)
3237 lr->e_address = e_address;
34d340d7 3238
cf37c299 3239 num_libraries++;
ef8ad44b 3240 }
cf37c299 3241
ef8ad44b
A
3242 if (type == LINKEDIT_R)
3243 break;
b51d5b5f 3244 }
cf37c299
A
3245
3246 free(fn_tofree);
3247
34d340d7
A
3248 if (fgets(buf, 1023, fd) == 0)
3249 break;
b51d5b5f 3250
34d340d7
A
3251 buf[strlen(buf)-1] = 0;
3252 }
cf37c299 3253
34d340d7 3254 fclose(fd);
b51d5b5f 3255
ef8ad44b
A
3256#if 0
3257 printf("%s range, %qx-%qx\n", path, lr->b_address, lr->e_address);
3258#endif
34d340d7
A
3259 return 1;
3260}
b51d5b5f 3261
cf37c299
A
3262void
3263init_shared_cache_mapping(void)
3264{
3265 read_shared_cache_map("/var/db/dyld/dyld_shared_cache_i386.map", &framework32, "/var/db/dyld/dyld_shared_cache_i386");
3266
3267 if (0 == read_shared_cache_map("/var/db/dyld/dyld_shared_cache_x86_64h.map", &framework64h, "/var/db/dyld/dyld_shared_cache_x86_64h")) {
3268 read_shared_cache_map("/var/db/dyld/dyld_shared_cache_x86_64.map", &framework64, "/var/db/dyld/dyld_shared_cache_x86_64");
3269 }
3270
3271 sort_library_addresses();
3272}
b51d5b5f 3273
34d340d7 3274void
cf37c299 3275lookup_name(uint64_t user_addr, char **type, char **name)
34d340d7 3276{
cf37c299
A
3277 int i;
3278 int start, last;
3279
3280 static char *frameworkType[] = {
3281 "<TEXT> ",
3282 "<DATA> ",
3283 "<OBJC> ",
3284 "<IMPORT> ",
3285 "<UNICODE> ",
3286 "<IMAGE> ",
3287 "<LINKEDIT>",
3288 };
3289
3290 *name = NULL;
3291 *type = NULL;
3292
3293 if (num_libraries) {
3294 if ((user_addr >= framework32.b_address && user_addr < framework32.e_address) ||
3295 (user_addr >= framework64.b_address && user_addr < framework64.e_address) ||
3296 (user_addr >= framework64h.b_address && user_addr < framework64h.e_address)) {
3297
3298 start = 0;
3299 last = num_libraries;
b51d5b5f 3300
cf37c299
A
3301 for (i = num_libraries / 2; start < last; i = start + ((last - start) / 2)) {
3302 if (user_addr > library_infos[i].e_address)
3303 start = i+1;
3304 else
3305 last = i;
3306 }
34d340d7 3307
cf37c299
A
3308 if (start < num_libraries &&
3309 user_addr >= library_infos[start].b_address && user_addr < library_infos[start].e_address) {
3310 *type = frameworkType[library_infos[start].r_type];
3311 *name = library_infos[start].name;
3312 }
3313 }
3314 }
b51d5b5f
A
3315}
3316
cf37c299 3317#pragma mark disk I/O tracking routines
b51d5b5f 3318
cf37c299
A
3319struct diskio *free_diskios = NULL;
3320struct diskio *busy_diskios = NULL;
3321
3322struct diskio *
3323diskio_start(unsigned long type, unsigned long bp, unsigned long dev,
3324 unsigned long blkno, unsigned long iosize, ktrace_event_t event)
b51d5b5f 3325{
cf37c299
A
3326 const char *command;
3327 struct diskio *dio;
3328
3329 if ((dio = free_diskios)) {
8459d725 3330 free_diskios = dio->next;
cf37c299
A
3331 } else {
3332 dio = malloc(sizeof (struct diskio));
8459d725 3333 }
cf37c299 3334
8459d725 3335 dio->prev = NULL;
cf37c299 3336
8459d725
A
3337 dio->type = type;
3338 dio->bp = bp;
3339 dio->dev = dev;
3340 dio->blkno = blkno;
cf37c299
A
3341 dio->iosize = iosize;
3342 dio->issued_time = event->timestamp;
3343 dio->issuing_thread = event->threadid;
3344 dio->issuing_pid = ktrace_get_pid_for_thread(s, event->threadid);
3345
fc6d9e4b 3346 dio->bc_info = 0x0;
cf37c299
A
3347
3348 command = ktrace_get_execname_for_thread(s, event->threadid);
3349
3350 if (!command)
3351 command = "";
3352
3353 strncpy(dio->issuing_command, command, MAXCOMLEN);
3354 dio->issuing_command[MAXCOMLEN] = '\0';
3355
8459d725 3356 dio->next = busy_diskios;
cf37c299 3357
8459d725
A
3358 if (dio->next)
3359 dio->next->prev = dio;
cf37c299 3360
8459d725 3361 busy_diskios = dio;
b51d5b5f 3362
cf37c299 3363 return dio;
b51d5b5f
A
3364}
3365
cf37c299
A
3366struct diskio *
3367diskio_find(unsigned long bp)
3368{
8459d725 3369 struct diskio *dio;
cf37c299 3370
8459d725 3371 for (dio = busy_diskios; dio; dio = dio->next) {
fc6d9e4b 3372 if (dio->bp == bp)
cf37c299 3373 return dio;
8459d725 3374 }
cf37c299 3375
fc6d9e4b
A
3376 return NULL;
3377}
3378
cf37c299
A
3379struct diskio *
3380diskio_complete(unsigned long bp, unsigned long io_errno, unsigned long resid,
3381 uintptr_t thread, uint64_t curtime, struct timeval curtime_wall)
fc6d9e4b
A
3382{
3383 struct diskio *dio;
cf37c299
A
3384
3385 if ((dio = diskio_find(bp)) == NULL) return NULL;
3386
fc6d9e4b
A
3387 if (dio == busy_diskios) {
3388 if ((busy_diskios = dio->next))
3389 dio->next->prev = NULL;
3390 } else {
3391 if (dio->next)
3392 dio->next->prev = dio->prev;
3393 dio->prev->next = dio->next;
3394 }
3395
3396 dio->iosize -= resid;
3397 dio->io_errno = io_errno;
3398 dio->completed_time = curtime;
cf37c299 3399 dio->completed_walltime = curtime_wall;
fc6d9e4b 3400 dio->completion_thread = thread;
cf37c299 3401
fc6d9e4b 3402 return dio;
b51d5b5f
A
3403}
3404
cf37c299
A
3405void
3406diskio_free(struct diskio *dio)
b51d5b5f 3407{
8459d725
A
3408 dio->next = free_diskios;
3409 free_diskios = dio;
b51d5b5f
A
3410}
3411
cf37c299
A
3412void
3413diskio_print(struct diskio *dio)
b51d5b5f 3414{
8459d725
A
3415 char *p = NULL;
3416 int len = 0;
cf37c299 3417 unsigned long type;
8459d725
A
3418 int format = FMT_DISKIO;
3419 char buf[64];
3420
3421 type = dio->type;
fc6d9e4b 3422 dio->is_meta = 0;
8459d725 3423
aaff5f01 3424 if ((type & P_CS_Class) == P_CS_Class) {
8459d725 3425 switch (type) {
cf37c299
A
3426 case P_CS_ReadChunk:
3427 p = " RdChunkCS";
3428 len = 13;
3429 format = FMT_DISKIO_CS;
3430 break;
3431 case P_CS_WriteChunk:
3432 p = " WrChunkCS";
3433 len = 13;
3434 format = FMT_DISKIO_CS;
3435 break;
3436 case P_CS_MetaRead:
3437 p = " RdMetaCS";
3438 len = 10;
3439 format = FMT_DISKIO_CS;
3440 break;
3441 case P_CS_MetaWrite:
3442 p = " WrMetaCS";
3443 len = 10;
3444 format = FMT_DISKIO_CS;
3445 break;
3446 case P_CS_TransformRead:
3447 p = " RdBgTfCS";
3448 len = 10;
3449 break;
3450 case P_CS_TransformWrite:
3451 p = " WrBgTfCS";
3452 len = 10;
3453 break;
3454 case P_CS_MigrationRead:
3455 p = " RdBgMigrCS";
3456 len = 12;
3457 break;
3458 case P_CS_MigrationWrite:
3459 p = " WrBgMigrCS";
3460 len = 12;
3461 break;
3462 default:
3463 p = " CS";
3464 len = 4;
3465 break;
8459d725 3466 }
cf37c299 3467
8459d725
A
3468 strncpy(buf, p, len);
3469 } else {
8459d725 3470 switch (type & P_DISKIO_TYPE) {
cf37c299
A
3471 case P_RdMeta:
3472 dio->is_meta = 1;
3473 p = " RdMeta";
3474 len = 8;
3475 break;
3476 case P_WrMeta:
3477 dio->is_meta = 1;
3478 p = " WrMeta";
3479 len = 8;
3480 break;
3481 case P_RdData:
3482 p = " RdData";
3483 len = 8;
3484 break;
3485 case P_WrData:
3486 p = " WrData";
3487 len = 8;
3488 break;
3489 case P_PgIn:
3490 p = " PgIn";
3491 len = 6;
3492 break;
3493 case P_PgOut:
3494 p = " PgOut";
3495 len = 7;
3496 break;
3497 default:
3498 p = " ";
3499 len = 2;
3500 break;
8459d725 3501 }
cf37c299 3502
8459d725
A
3503 strncpy(buf, p, len);
3504
aaff5f01 3505 buf[len++] = '[';
cf37c299 3506
aaff5f01
A
3507 if (type & P_DISKIO_ASYNC)
3508 buf[len++] = 'A';
3509 else
3510 buf[len++] = 'S';
8459d725 3511
aaff5f01
A
3512 if (type & P_DISKIO_NOCACHE)
3513 buf[len++] = 'N';
3514
fc6d9e4b 3515 int tier = (type & P_DISKIO_TIER_MASK) >> P_DISKIO_TIER_SHIFT;
cf37c299 3516
fc6d9e4b 3517 if (tier > 0) {
aaff5f01 3518 buf[len++] = 'T';
fc6d9e4b
A
3519 if (tier > 0 && tier < 10)
3520 buf[len++] = '0' + tier;
3521 }
3522
3523 if (type & P_DISKIO_PASSIVE)
aaff5f01
A
3524 buf[len++] = 'P';
3525
3526 buf[len++] = ']';
8459d725 3527 }
cf37c299 3528
8459d725
A
3529 buf[len] = 0;
3530
cf37c299
A
3531 if (check_filter_mode(-1, NULL, type, 0, 0, buf))
3532 format_print(NULL, buf, NULL, type, format, dio->completed_time, dio->issued_time, 1, "", dio);
b51d5b5f
A
3533}
3534
cf37c299
A
3535#pragma mark disk name routines
3536
3537struct diskrec {
3538 struct diskrec *next;
3539 char *diskname;
3540 int dev;
3541};
3542
3543struct diskrec *disk_list = NULL;
b51d5b5f 3544
cf37c299
A
3545void
3546cache_disk_names(void)
b51d5b5f 3547{
8459d725
A
3548 struct stat st;
3549 DIR *dirp = NULL;
3550 struct dirent *dir;
3551 struct diskrec *dnp;
b51d5b5f 3552
8459d725
A
3553 if ((dirp = opendir("/dev")) == NULL)
3554 return;
cf37c299 3555
8459d725
A
3556 while ((dir = readdir(dirp)) != NULL) {
3557 char nbuf[MAXPATHLEN];
cf37c299 3558
8459d725
A
3559 if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
3560 continue;
3561
3562 snprintf(nbuf, MAXPATHLEN, "%s/%s", "/dev", dir->d_name);
cf37c299 3563
8459d725
A
3564 if (stat(nbuf, &st) < 0)
3565 continue;
b51d5b5f 3566
cf37c299 3567 if ((dnp = malloc(sizeof(struct diskrec))) == NULL)
8459d725 3568 continue;
cf37c299
A
3569
3570 if ((dnp->diskname = malloc(dir->d_namlen + 1)) == NULL) {
8459d725
A
3571 free(dnp);
3572 continue;
3573 }
3574 strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
3575 dnp->diskname[dir->d_namlen] = 0;
3576 dnp->dev = st.st_rdev;
cf37c299 3577
8459d725
A
3578 dnp->next = disk_list;
3579 disk_list = dnp;
3580 }
b51d5b5f 3581
cf37c299
A
3582 closedir(dirp);
3583}
b51d5b5f 3584
cf37c299
A
3585static void
3586recache_disk_names(void)
ef8ad44b
A
3587{
3588 struct diskrec *dnp, *next_dnp;
3589
3590 for (dnp = disk_list; dnp; dnp = next_dnp) {
3591 next_dnp = dnp->next;
3592
3593 free(dnp->diskname);
3594 free(dnp);
3595 }
ef8ad44b 3596
cf37c299 3597 disk_list = NULL;
ef8ad44b
A
3598 cache_disk_names();
3599}
3600
cf37c299
A
3601char *
3602find_disk_name(unsigned long dev)
b51d5b5f 3603{
8459d725
A
3604 struct diskrec *dnp;
3605 int i;
cf37c299 3606
8459d725
A
3607 if (dev == NFS_DEV)
3608 return ("NFS");
cf37c299 3609
8459d725
A
3610 if (dev == CS_DEV)
3611 return ("CS");
cf37c299 3612
8459d725
A
3613 for (i = 0; i < 2; i++) {
3614 for (dnp = disk_list; dnp; dnp = dnp->next) {
3615 if (dnp->dev == dev)
3616 return (dnp->diskname);
3617 }
3618 recache_disk_names();
20e66415 3619 }
20e66415 3620
cf37c299 3621 return "NOTFOUND";
20e66415
A
3622}
3623
cf37c299
A
3624char *
3625generate_cs_disk_name(unsigned long dev, char *s)
20e66415 3626{
cf37c299
A
3627 if (dev == -1)
3628 return "UNKNOWN";
20e66415 3629
cf37c299 3630 sprintf(s, "disk%lus%lu", (dev >> 16) & 0xffff, dev & 0xffff);
20e66415 3631
cf37c299 3632 return (s);
20e66415 3633}