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