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