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