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