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