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