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