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