2 * Copyright (c) 1999-2020 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
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
42 #include <TargetConditionals.h>
44 #include <ktrace/session.h>
45 #include <System/sys/kdebug.h>
46 #include <os/assumes.h>
49 #include <sys/fcntl.h>
51 #include <sys/ioctl.h>
53 #include <sys/param.h>
54 #include <sys/socket.h>
55 #include <sys/syslimits.h>
57 #include <sys/types.h>
59 #import <mach/clock_types.h>
60 #import <mach/mach_time.h>
63 * MAXCOLS controls when extra data kicks in.
64 * MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
67 #define MAX_WIDE_MODE_COLS 264
68 #define MAXWIDTH MAX_WIDE_MODE_COLS + 64
70 typedef struct th_info
{
74 /* this is needed for execve()/posix_spawn(), because the command name at the end probe is the new name, which we don't want */
75 char command
[MAXCOMLEN
+ 1];
78 * sometimes a syscall can cause multiple VFS_LOOKUPs of the same vnode with multiple paths
79 * (e.g., one absolute, one relative). traditional fs_usage behavior was to display the
80 * *first* lookup, so we need to save it off once we see it.
82 uint64_t vnodeid
; /* the vp of the VFS_LOOKUP we're currently in, 0 if we are not in one */
83 char pathname
[MAXPATHLEN
];
84 char pathname2
[MAXPATHLEN
];
85 char *newest_pathname
; /* points to pathname2 if it's filled, otherwise pathname if it's filled, otherwise NULL */
112 uint64_t issuing_thread
;
114 uint64_t completion_thread
;
115 char issuing_command
[MAXCOMLEN
+ 1];
116 uint64_t issued_time
;
117 uint64_t completed_time
;
118 struct timeval completed_walltime
;
122 #define HASH_SIZE 1024
123 #define HASH_MASK (HASH_SIZE - 1)
125 void setup_ktrace_callbacks(void);
126 void extend_syscall(uint64_t thread
, int type
, ktrace_event_t event
);
128 /* printing routines */
129 bool check_filter_mode(pid_t pid
, th_info_t ti
, uint64_t type
, int error
, int retval
, char *sc_name
);
130 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
);
131 int print_open(ktrace_event_t event
, uint64_t flags
);
133 /* metadata info hash routines */
134 void meta_add_name(uint64_t blockno
, const char *pathname
);
135 const char *meta_find_name(uint64_t blockno
);
136 void meta_delete_all(void);
138 /* event ("thread info") routines */
139 void event_enter(int type
, ktrace_event_t event
);
140 void event_exit(char *sc_name
, int type
, ktrace_event_t event
, int format
);
141 th_info_t
event_find(uint64_t thread
, int type
);
142 void event_delete(th_info_t ti_to_delete
);
143 void event_delete_all(void);
144 void event_mark_thread_waited(uint64_t);
146 /* network fd set routines */
147 void fd_set_is_network(pid_t pid
, uint64_t fd
, bool set
);
148 bool fd_is_network(pid_t pid
, uint64_t fd
);
149 void fd_clear_pid(pid_t pid
);
150 void fd_clear_all(void);
152 /* shared region address lookup routines */
153 void init_shared_cache_mapping(void);
154 void lookup_name(uint64_t user_addr
, char **type
, char **name
);
156 /* disk I/O tracking routines */
157 struct diskio
*diskio_start(uint64_t type
, uint64_t bp
, uint64_t dev
, uint64_t blkno
, uint64_t iosize
, ktrace_event_t event
);
158 struct diskio
*diskio_find(uint64_t bp
);
159 struct diskio
*diskio_complete(uint64_t bp
, uint64_t io_errno
, uint64_t resid
, uint64_t thread
, uint64_t curtime
, struct timeval curtime_wall
);
160 void diskio_print(struct diskio
*dio
);
161 void diskio_free(struct diskio
*dio
);
163 /* disk name routines */
166 char *generate_cs_disk_name(uint64_t dev
, char *s
);
167 char *find_disk_name(uint64_t dev
);
168 void cache_disk_names(void);
170 #define CLASS_MASK 0xff000000
171 #define CSC_MASK 0xffff0000
172 #define BSC_INDEX(type) ((type >> 2) & 0x3fff)
174 #define MACH_vmfault 0x01300008
175 #define MACH_pageout 0x01300004
176 #define MACH_sched 0x01400000
177 #define MACH_stkhandoff 0x01400008
178 #define MACH_idle 0x01400024
180 #define BSC_thread_terminate 0x040c05a4
182 #define HFS_update 0x3018000
183 #define HFS_modify_block_end 0x3018004
185 #define Throttled 0x3010184
186 #define SPEC_ioctl 0x3060000
187 #define SPEC_unmap_info 0x3060004
188 #define proc_exit 0x4010004
190 #define BC_IO_HIT 0x03070010
191 #define BC_IO_HIT_STALLED 0x03070020
192 #define BC_IO_MISS 0x03070040
193 #define BC_IO_MISS_CUT_THROUGH 0x03070080
194 #define BC_PLAYBACK_IO 0x03070100
195 #define BC_STR(s) ( \
196 (s == BC_IO_HIT) ? "HIT" : \
197 (s == BC_IO_HIT_STALLED) ? "STALL" : \
198 (s == BC_IO_MISS) ? "MISS" : \
199 (s == BC_IO_MISS_CUT_THROUGH) ? "CUT" : \
200 (s == BC_PLAYBACK_IO) ? "PLBK" : \
201 (s == 0x0) ? "NONE" : "UNKN" )
203 #define P_DISKIO_READ (DKIO_READ << 2)
204 #define P_DISKIO_ASYNC (DKIO_ASYNC << 2)
205 #define P_DISKIO_META (DKIO_META << 2)
206 #define P_DISKIO_PAGING (DKIO_PAGING << 2)
207 #define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
208 #define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
209 #define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
210 #define P_DISKIO_TIER_MASK (DKIO_TIER_MASK << 2)
211 #define P_DISKIO_TIER_SHIFT (DKIO_TIER_SHIFT + 2)
212 #define P_DISKIO_TIER_UPGRADE (DKIO_TIER_UPGRADE << 2)
214 #define P_DISKIO (FSDBG_CODE(DBG_DKRW, 0))
215 #define P_DISKIO_DONE (P_DISKIO | (DKIO_DONE << 2))
216 #define P_DISKIO_TYPE (P_DISKIO | P_DISKIO_READ | P_DISKIO_META | P_DISKIO_PAGING)
217 #define P_DISKIO_MASK (CSC_MASK | 0x4)
219 #define P_WrData (P_DISKIO)
220 #define P_RdData (P_DISKIO | P_DISKIO_READ)
221 #define P_WrMeta (P_DISKIO | P_DISKIO_META)
222 #define P_RdMeta (P_DISKIO | P_DISKIO_META | P_DISKIO_READ)
223 #define P_PgOut (P_DISKIO | P_DISKIO_PAGING)
224 #define P_PgIn (P_DISKIO | P_DISKIO_PAGING | P_DISKIO_READ)
226 #define P_CS_Class 0x0a000000 // DBG_CORESTORAGE
227 #define P_CS_Type_Mask 0xfffffff0
228 #define P_CS_IO_Done 0x00000004
230 #define P_CS_ReadChunk 0x0a000200 // chopped up request
231 #define P_CS_WriteChunk 0x0a000210
232 #define P_CS_MetaRead 0x0a000300 // meta data
233 #define P_CS_MetaWrite 0x0a000310
234 #define P_CS_TransformRead 0x0a000500 // background transform
235 #define P_CS_TransformWrite 0x0a000510
236 #define P_CS_MigrationRead 0x0a000600 // composite disk block migration
237 #define P_CS_MigrationWrite 0x0a000610
238 #define P_CS_SYNC_DISK 0x0a010000
240 #define MSC_map_fd 0x010c00ac
242 #define BSC_BASE 0x040C0000
244 // Network related codes
245 #define BSC_recvmsg 0x040C006C
246 #define BSC_sendmsg 0x040C0070
247 #define BSC_recvfrom 0x040C0074
248 #define BSC_accept 0x040C0078
249 #define BSC_select 0x040C0174
250 #define BSC_socket 0x040C0184
251 #define BSC_connect 0x040C0188
252 #define BSC_bind 0x040C01A0
253 #define BSC_listen 0x040C01A8
254 #define BSC_sendto 0x040C0214
255 #define BSC_socketpair 0x040C021C
256 #define BSC_recvmsg_nocancel 0x040c0644
257 #define BSC_sendmsg_nocancel 0x040c0648
258 #define BSC_recvfrom_nocancel 0x040c064c
259 #define BSC_accept_nocancel 0x040c0650
260 #define BSC_connect_nocancel 0x040c0664
261 #define BSC_sendto_nocancel 0x040c0674
263 #define BSC_exit 0x040C0004
264 #define BSC_read 0x040C000C
265 #define BSC_write 0x040C0010
266 #define BSC_open 0x040C0014
267 #define BSC_close 0x040C0018
268 #define BSC_link 0x040C0024
269 #define BSC_unlink 0x040C0028
270 #define BSC_chdir 0x040c0030
271 #define BSC_fchdir 0x040c0034
272 #define BSC_mknod 0x040C0038
273 #define BSC_chmod 0x040C003C
274 #define BSC_chown 0x040C0040
275 #define BSC_getfsstat 0x040C0048
276 #define BSC_access 0x040C0084
277 #define BSC_chflags 0x040C0088
278 #define BSC_fchflags 0x040C008C
279 #define BSC_sync 0x040C0090
280 #define BSC_dup 0x040C00A4
281 #define BSC_ioctl 0x040C00D8
282 #define BSC_revoke 0x040C00E0
283 #define BSC_symlink 0x040C00E4
284 #define BSC_readlink 0x040C00E8
285 #define BSC_execve 0x040C00EC
286 #define BSC_umask 0x040C00F0
287 #define BSC_chroot 0x040C00F4
288 #define BSC_msync 0x040C0104
289 #define BSC_dup2 0x040C0168
290 #define BSC_fcntl 0x040C0170
291 #define BSC_fsync 0x040C017C
292 #define BSC_readv 0x040C01E0
293 #define BSC_writev 0x040C01E4
294 #define BSC_fchown 0x040C01EC
295 #define BSC_fchmod 0x040C01F0
296 #define BSC_rename 0x040C0200
297 #define BSC_flock 0x040C020C
298 #define BSC_mkfifo 0x040C0210
299 #define BSC_mkdir 0x040C0220
300 #define BSC_rmdir 0x040C0224
301 #define BSC_utimes 0x040C0228
302 #define BSC_futimes 0x040C022C
303 #define BSC_pread 0x040C0264
304 #define BSC_pwrite 0x040C0268
305 #define BSC_statfs 0x040C0274
306 #define BSC_fstatfs 0x040C0278
307 #define BSC_unmount 0x040C027C
308 #define BSC_mount 0x040C029C
309 #define BSC_fdatasync 0x040C02EC
310 #define BSC_stat 0x040C02F0
311 #define BSC_fstat 0x040C02F4
312 #define BSC_lstat 0x040C02F8
313 #define BSC_pathconf 0x040C02FC
314 #define BSC_fpathconf 0x040C0300
315 #define BSC_getdirentries 0x040C0310
316 #define BSC_mmap 0x040c0314
317 #define BSC_lseek 0x040c031c
318 #define BSC_truncate 0x040C0320
319 #define BSC_ftruncate 0x040C0324
320 #define BSC_undelete 0x040C0334
321 #define BSC_open_dprotected_np 0x040C0360
322 #define BSC_getattrlist 0x040C0370
323 #define BSC_setattrlist 0x040C0374
324 #define BSC_getdirentriesattr 0x040C0378
325 #define BSC_exchangedata 0x040C037C
326 #define BSC_checkuseraccess 0x040C0380
327 #define BSC_searchfs 0x040C0384
328 #define BSC_delete 0x040C0388
329 #define BSC_copyfile 0x040C038C
330 #define BSC_fgetattrlist 0x040C0390
331 #define BSC_fsetattrlist 0x040C0394
332 #define BSC_getxattr 0x040C03A8
333 #define BSC_fgetxattr 0x040C03AC
334 #define BSC_setxattr 0x040C03B0
335 #define BSC_fsetxattr 0x040C03B4
336 #define BSC_removexattr 0x040C03B8
337 #define BSC_fremovexattr 0x040C03BC
338 #define BSC_listxattr 0x040C03C0
339 #define BSC_flistxattr 0x040C03C4
340 #define BSC_fsctl 0x040C03C8
341 #define BSC_posix_spawn 0x040C03D0
342 #define BSC_ffsctl 0x040C03D4
343 #define BSC_open_extended 0x040C0454
344 #define BSC_umask_extended 0x040C0458
345 #define BSC_stat_extended 0x040C045C
346 #define BSC_lstat_extended 0x040C0460
347 #define BSC_fstat_extended 0x040C0464
348 #define BSC_chmod_extended 0x040C0468
349 #define BSC_fchmod_extended 0x040C046C
350 #define BSC_access_extended 0x040C0470
351 #define BSC_mkfifo_extended 0x040C048C
352 #define BSC_mkdir_extended 0x040C0490
353 #define BSC_aio_fsync 0x040C04E4
354 #define BSC_aio_return 0x040C04E8
355 #define BSC_aio_suspend 0x040C04EC
356 #define BSC_aio_cancel 0x040C04F0
357 #define BSC_aio_error 0x040C04F4
358 #define BSC_aio_read 0x040C04F8
359 #define BSC_aio_write 0x040C04FC
360 #define BSC_lio_listio 0x040C0500
361 #define BSC_sendfile 0x040C0544
362 #define BSC_stat64 0x040C0548
363 #define BSC_fstat64 0x040C054C
364 #define BSC_lstat64 0x040C0550
365 #define BSC_stat64_extended 0x040C0554
366 #define BSC_lstat64_extended 0x040C0558
367 #define BSC_fstat64_extended 0x040C055C
368 #define BSC_getdirentries64 0x040C0560
369 #define BSC_statfs64 0x040C0564
370 #define BSC_fstatfs64 0x040C0568
371 #define BSC_getfsstat64 0x040C056C
372 #define BSC_pthread_chdir 0x040C0570
373 #define BSC_pthread_fchdir 0x040C0574
374 #define BSC_lchown 0x040C05B0
376 #define BSC_read_nocancel 0x040c0630
377 #define BSC_write_nocancel 0x040c0634
378 #define BSC_open_nocancel 0x040c0638
379 #define BSC_close_nocancel 0x040c063c
380 #define BSC_msync_nocancel 0x040c0654
381 #define BSC_fcntl_nocancel 0x040c0658
382 #define BSC_select_nocancel 0x040c065c
383 #define BSC_fsync_nocancel 0x040c0660
384 #define BSC_readv_nocancel 0x040c066c
385 #define BSC_writev_nocancel 0x040c0670
386 #define BSC_pread_nocancel 0x040c0678
387 #define BSC_pwrite_nocancel 0x040c067c
388 #define BSC_aio_suspend_nocancel 0x40c0694
389 #define BSC_guarded_open_np 0x040c06e4
390 #define BSC_guarded_open_dprotected_np 0x040c0790
391 #define BSC_guarded_close_np 0x040c06e8
392 #define BSC_guarded_write_np 0x040c0794
393 #define BSC_guarded_pwrite_np 0x040c0798
394 #define BSC_guarded_writev_np 0x040c079c
396 #define BSC_fsgetpath 0x040c06ac
398 #define BSC_getattrlistbulk 0x040c0734
400 #define BSC_openat 0x040c073c
401 #define BSC_openat_nocancel 0x040c0740
402 #define BSC_renameat 0x040c0744
403 #define BSC_chmodat 0x040c074c
404 #define BSC_chownat 0x040c0750
405 #define BSC_fstatat 0x040c0754
406 #define BSC_fstatat64 0x040c0758
407 #define BSC_linkat 0x040c075c
408 #define BSC_unlinkat 0x040c0760
409 #define BSC_readlinkat 0x040c0764
410 #define BSC_symlinkat 0x040c0768
411 #define BSC_mkdirat 0x040c076c
412 #define BSC_getattrlistat 0x040c0770
414 #define BSC_msync_extended 0x040e0104
415 #define BSC_pread_extended 0x040e0264
416 #define BSC_pwrite_extended 0x040e0268
417 #define BSC_guarded_pwrite_extended 0x040e0798
418 #define BSC_mmap_extended 0x040e0314
419 #define BSC_mmap_extended2 0x040f0314
421 #define FMT_NOTHING -1
422 #define FMT_DEFAULT 0
429 #define FMT_CACHEHIT 7
433 #define FMT_FTRUNC 11
435 #define FMT_SELECT 13
437 #define FMT_AIO_FSYNC 15
438 #define FMT_AIO_RETURN 16
439 #define FMT_AIO_SUSPEND 17
440 #define FMT_AIO_CANCEL 18
442 #define FMT_LIO_LISTIO 20
445 #define FMT_ACCESS 23
447 #define FMT_FCHMOD 25
448 #define FMT_CHMOD_EXT 26
449 #define FMT_FCHMOD_EXT 27
450 #define FMT_CHFLAGS 28
451 #define FMT_FCHFLAGS 29
455 #define FMT_SENDFILE 33
456 #define FMT_IOCTL_SYNC 34
458 #define FMT_UNMOUNT 36
459 #define FMT_DISKIO_CS 37
460 #define FMT_SYNC_DISK_CS 38
461 #define FMT_IOCTL_UNMAP 39
462 #define FMT_UNMAP_INFO 40
463 #define FMT_HFS_update 41
466 #define FMT_CHMODAT 44
467 #define FMT_OPENAT 45
468 #define FMT_RENAMEAT 46
469 #define FMT_IOCTL_SYNCCACHE 47
470 #define FMT_GUARDED_OPEN 48
472 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
474 #pragma mark global state
477 bool BC_flag
= false;
478 bool RAW_flag
= false;
479 bool wideflag
= false;
480 bool include_waited_flag
= false;
481 bool want_kernel_task
= true;
482 dispatch_source_t stop_timer
, sigquit_source
, sigpipe_source
, sighup_source
, sigterm_source
, sigwinch_source
;
483 uint64_t mach_time_of_first_event
;
484 uint64_t start_time_ns
= 0;
485 uint64_t end_time_ns
= UINT64_MAX
;
486 unsigned int columns
= 0;
489 * Network only or filesystem only output filter
490 * Default of zero means report all activity - no filtering
492 #define FILESYS_FILTER 0x01
493 #define NETWORK_FILTER 0x02
494 #define EXEC_FILTER 0x08
495 #define PATHNAME_FILTER 0x10
496 #define DISKIO_FILTER 0x20
497 #define DEFAULT_DO_NOT_FILTER 0x00
499 int filter_mode
= DEFAULT_DO_NOT_FILTER
;
500 bool show_cachehits
= false;
502 #pragma mark syscall lookup table
504 #define MAX_BSD_SYSCALL 526
511 #define NORMAL_SYSCALL(name) \
512 [BSC_INDEX(BSC_##name)] = {#name, FMT_DEFAULT}
514 #define SYSCALL(name, format) \
515 [BSC_INDEX(BSC_##name)] = {#name, format}
517 #define SYSCALL_NAMED(name, displayname, format) \
518 [BSC_INDEX(BSC_##name)] = {#displayname, format}
520 #define SYSCALL_WITH_NOCANCEL(name, format) \
521 [BSC_INDEX(BSC_##name)] = {#name, format}, \
522 [BSC_INDEX(BSC_##name##_nocancel)] = {#name, format}
524 const struct bsd_syscall bsd_syscalls
[MAX_BSD_SYSCALL
] = {
525 SYSCALL(sendfile
, FMT_FD
), /* this should be changed to FMT_SENDFILE once we add an extended info trace event */
526 SYSCALL_WITH_NOCANCEL(recvmsg
, FMT_FD_IO
),
527 SYSCALL_WITH_NOCANCEL(sendmsg
, FMT_FD_IO
),
528 SYSCALL_WITH_NOCANCEL(recvfrom
, FMT_FD_IO
),
529 SYSCALL_WITH_NOCANCEL(sendto
, FMT_FD_IO
),
530 SYSCALL_WITH_NOCANCEL(select
, FMT_SELECT
),
531 SYSCALL_WITH_NOCANCEL(accept
, FMT_FD_2
),
532 SYSCALL(socket
, FMT_SOCKET
),
533 SYSCALL_WITH_NOCANCEL(connect
, FMT_FD
),
534 SYSCALL(bind
, FMT_FD
),
535 SYSCALL(listen
, FMT_FD
),
536 SYSCALL(mmap
, FMT_MMAP
),
537 NORMAL_SYSCALL(socketpair
),
538 NORMAL_SYSCALL(getxattr
),
539 NORMAL_SYSCALL(setxattr
),
540 NORMAL_SYSCALL(removexattr
),
541 NORMAL_SYSCALL(listxattr
),
542 NORMAL_SYSCALL(stat
),
543 NORMAL_SYSCALL(stat64
),
544 NORMAL_SYSCALL(stat_extended
),
545 SYSCALL_NAMED(stat64_extended
, stat_extended64
, FMT_DEFAULT
), /* should be stat64_extended ? */
546 SYSCALL(mount
, FMT_MOUNT
),
547 SYSCALL(unmount
, FMT_UNMOUNT
),
548 NORMAL_SYSCALL(exit
),
549 NORMAL_SYSCALL(execve
),
550 NORMAL_SYSCALL(posix_spawn
),
551 SYSCALL_WITH_NOCANCEL(open
, FMT_OPEN
),
552 SYSCALL(open_extended
, FMT_OPEN
),
553 SYSCALL(guarded_open_np
, FMT_GUARDED_OPEN
),
554 SYSCALL_NAMED(open_dprotected_np
, open_dprotected
, FMT_OPEN
),
555 SYSCALL(guarded_open_dprotected_np
, FMT_GUARDED_OPEN
),
556 SYSCALL(dup
, FMT_FD_2
),
557 SYSCALL(dup2
, FMT_FD_2
),
558 SYSCALL_WITH_NOCANCEL(close
, FMT_FD
),
559 SYSCALL(guarded_close_np
, FMT_FD
),
560 SYSCALL_WITH_NOCANCEL(read
, FMT_FD_IO
),
561 SYSCALL_WITH_NOCANCEL(write
, FMT_FD_IO
),
562 SYSCALL(guarded_write_np
, FMT_FD_IO
),
563 SYSCALL(guarded_pwrite_np
, FMT_PREAD
),
564 SYSCALL(guarded_writev_np
, FMT_FD_IO
),
565 SYSCALL(fgetxattr
, FMT_FD
),
566 SYSCALL(fsetxattr
, FMT_FD
),
567 SYSCALL(fremovexattr
, FMT_FD
),
568 SYSCALL(flistxattr
, FMT_FD
),
569 SYSCALL(fstat
, FMT_FD
),
570 SYSCALL(fstat64
, FMT_FD
),
571 SYSCALL(fstat_extended
, FMT_FD
),
572 SYSCALL(fstat64_extended
, FMT_FD
),
573 NORMAL_SYSCALL(lstat
),
574 NORMAL_SYSCALL(lstat64
),
575 NORMAL_SYSCALL(lstat_extended
),
576 SYSCALL_NAMED(lstat64_extended
, lstat_extended64
, FMT_DEFAULT
),
577 NORMAL_SYSCALL(link
),
578 NORMAL_SYSCALL(unlink
),
579 NORMAL_SYSCALL(mknod
),
580 SYSCALL(umask
, FMT_UMASK
),
581 SYSCALL(umask_extended
, FMT_UMASK
),
582 SYSCALL(chmod
, FMT_CHMOD
),
583 SYSCALL(chmod_extended
, FMT_CHMOD_EXT
),
584 SYSCALL(fchmod
, FMT_FCHMOD
),
585 SYSCALL(fchmod_extended
, FMT_FCHMOD_EXT
),
586 NORMAL_SYSCALL(chown
),
587 NORMAL_SYSCALL(lchown
),
588 SYSCALL(fchown
, FMT_FD
),
589 SYSCALL(access
, FMT_ACCESS
),
590 NORMAL_SYSCALL(access_extended
),
591 NORMAL_SYSCALL(chdir
),
592 NORMAL_SYSCALL(pthread_chdir
),
593 NORMAL_SYSCALL(chroot
),
594 NORMAL_SYSCALL(utimes
),
595 SYSCALL_NAMED(delete, delete-Carbon
, FMT_DEFAULT
),
596 NORMAL_SYSCALL(undelete
),
597 NORMAL_SYSCALL(revoke
),
598 NORMAL_SYSCALL(fsctl
),
599 SYSCALL(ffsctl
, FMT_FD
),
600 SYSCALL(chflags
, FMT_CHFLAGS
),
601 SYSCALL(fchflags
, FMT_FCHFLAGS
),
602 SYSCALL(fchdir
, FMT_FD
),
603 SYSCALL(pthread_fchdir
, FMT_FD
),
604 SYSCALL(futimes
, FMT_FD
),
605 NORMAL_SYSCALL(sync
),
606 NORMAL_SYSCALL(symlink
),
607 NORMAL_SYSCALL(readlink
),
608 SYSCALL_WITH_NOCANCEL(fsync
, FMT_FD
),
609 SYSCALL(fdatasync
, FMT_FD
),
610 SYSCALL_WITH_NOCANCEL(readv
, FMT_FD_IO
),
611 SYSCALL_WITH_NOCANCEL(writev
, FMT_FD_IO
),
612 SYSCALL_WITH_NOCANCEL(pread
, FMT_PREAD
),
613 SYSCALL_WITH_NOCANCEL(pwrite
, FMT_PREAD
),
614 NORMAL_SYSCALL(mkdir
),
615 NORMAL_SYSCALL(mkdir_extended
),
616 NORMAL_SYSCALL(mkfifo
),
617 NORMAL_SYSCALL(mkfifo_extended
),
618 NORMAL_SYSCALL(rmdir
),
619 NORMAL_SYSCALL(statfs
),
620 NORMAL_SYSCALL(statfs64
),
621 NORMAL_SYSCALL(getfsstat
),
622 NORMAL_SYSCALL(getfsstat64
),
623 SYSCALL(fstatfs
, FMT_FD
),
624 SYSCALL(fstatfs64
, FMT_FD
),
625 NORMAL_SYSCALL(pathconf
),
626 SYSCALL(fpathconf
, FMT_FD
),
627 SYSCALL(getdirentries
, FMT_FD_IO
),
628 SYSCALL(getdirentries64
, FMT_FD_IO
),
629 SYSCALL(lseek
, FMT_LSEEK
),
630 SYSCALL(truncate
, FMT_TRUNC
),
631 SYSCALL(ftruncate
, FMT_FTRUNC
),
632 SYSCALL(flock
, FMT_FLOCK
),
633 NORMAL_SYSCALL(getattrlist
),
634 NORMAL_SYSCALL(setattrlist
),
635 SYSCALL(fgetattrlist
, FMT_FD
),
636 SYSCALL(fsetattrlist
, FMT_FD
),
637 SYSCALL(getdirentriesattr
, FMT_FD
),
638 NORMAL_SYSCALL(exchangedata
),
639 NORMAL_SYSCALL(rename
),
640 NORMAL_SYSCALL(copyfile
),
641 NORMAL_SYSCALL(checkuseraccess
),
642 NORMAL_SYSCALL(searchfs
),
643 SYSCALL(aio_fsync
, FMT_AIO_FSYNC
),
644 SYSCALL(aio_return
, FMT_AIO_RETURN
),
645 SYSCALL_WITH_NOCANCEL(aio_suspend
, FMT_AIO_SUSPEND
),
646 SYSCALL(aio_cancel
, FMT_AIO_CANCEL
),
647 SYSCALL(aio_error
, FMT_AIO
),
648 SYSCALL(aio_read
, FMT_AIO
),
649 SYSCALL(aio_write
, FMT_AIO
),
650 SYSCALL(lio_listio
, FMT_LIO_LISTIO
),
651 SYSCALL_WITH_NOCANCEL(msync
, FMT_MSYNC
),
652 SYSCALL_WITH_NOCANCEL(fcntl
, FMT_FCNTL
),
653 SYSCALL(ioctl
, FMT_IOCTL
),
654 NORMAL_SYSCALL(fsgetpath
),
655 NORMAL_SYSCALL(getattrlistbulk
),
656 SYSCALL_WITH_NOCANCEL(openat
, FMT_OPENAT
), /* open_nocancel() was previously shown as "open_nocanel" (note spelling) */
657 SYSCALL(renameat
, FMT_RENAMEAT
),
658 SYSCALL(chmodat
, FMT_CHMODAT
),
659 SYSCALL(chownat
, FMT_AT
),
660 SYSCALL(fstatat
, FMT_AT
),
661 SYSCALL(fstatat64
, FMT_AT
),
662 SYSCALL(linkat
, FMT_AT
),
663 SYSCALL(unlinkat
, FMT_AT
),
664 SYSCALL(readlinkat
, FMT_AT
),
665 SYSCALL(symlinkat
, FMT_AT
),
666 SYSCALL(mkdirat
, FMT_AT
),
667 SYSCALL(getattrlistat
, FMT_AT
),
671 get_screenwidth(void)
677 if (isatty(STDOUT_FILENO
)) {
678 if (ioctl(1, TIOCGWINSZ
, &size
) != -1) {
679 columns
= size
.ws_col
;
681 if (columns
> MAXWIDTH
)
688 mach_to_nano(uint64_t mach
)
690 uint64_t nanoseconds
= 0;
691 os_assert(ktrace_convert_timestamp_to_nanoseconds(s
, mach
, &nanoseconds
) == 0);
701 myname
= getprogname();
703 fprintf(stderr
, "Usage: %s [-e] [-w] [-f mode] [-b] [-t seconds] [-R rawfile [-S start_time] [-E end_time]] [pid | cmd [pid | cmd] ...]\n", myname
);
704 fprintf(stderr
, " -e exclude the specified list of pids from the sample\n");
705 fprintf(stderr
, " and exclude fs_usage by default\n");
706 fprintf(stderr
, " -w force wider, detailed, output\n");
707 fprintf(stderr
, " -f output is based on the mode provided\n");
708 fprintf(stderr
, " mode = \"network\" Show network-related events\n");
709 fprintf(stderr
, " mode = \"filesys\" Show filesystem-related events\n");
710 fprintf(stderr
, " mode = \"pathname\" Show only pathname-related events\n");
711 fprintf(stderr
, " mode = \"exec\" Show only exec and spawn events\n");
712 fprintf(stderr
, " mode = \"diskio\" Show only disk I/O events\n");
713 fprintf(stderr
, " mode = \"cachehit\" In addition, show cache hits\n");
714 fprintf(stderr
, " -b annotate disk I/O events with BootCache info (if available)\n");
715 fprintf(stderr
, " -t specifies timeout in seconds (for use in automated tools)\n");
716 fprintf(stderr
, " -R specifies a raw trace file to process\n");
717 fprintf(stderr
, " -S if -R is specified, selects a start point in microseconds\n");
718 fprintf(stderr
, " -E if -R is specified, selects an end point in microseconds\n");
719 fprintf(stderr
, " pid selects process(s) to sample\n");
720 fprintf(stderr
, " cmd selects process(s) matching command string to sample\n");
721 fprintf(stderr
, "By default (no options) the following processes are excluded from the output:\n");
722 fprintf(stderr
, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");
727 static void fs_usage_cleanup(const char *message
)
730 ktrace_session_destroy(s
);
733 fprintf(stderr
, "Cleaning up tracing state because of %s\n", message
);
737 main(int argc
, char *argv
[])
741 bool exclude_pids
= false;
742 uint64_t time_limit_ns
= 0;
744 os_set_crash_callback(&fs_usage_cleanup
);
748 s
= ktrace_session_create();
749 os_assert(s
!= NULL
);
750 (void)ktrace_ignore_process_filter_for_event(s
, P_WrData
);
751 (void)ktrace_ignore_process_filter_for_event(s
, P_RdData
);
752 (void)ktrace_ignore_process_filter_for_event(s
, P_WrMeta
);
753 (void)ktrace_ignore_process_filter_for_event(s
, P_RdMeta
);
754 (void)ktrace_ignore_process_filter_for_event(s
, P_PgOut
);
755 (void)ktrace_ignore_process_filter_for_event(s
, P_PgIn
);
757 while ((ch
= getopt(argc
, argv
, "bewf:R:S:E:t:W")) != -1) {
765 columns
= MAX_WIDE_MODE_COLS
;
769 include_waited_flag
= true;
773 if (!strcmp(optarg
, "network"))
774 filter_mode
|= NETWORK_FILTER
;
775 else if (!strcmp(optarg
, "filesys"))
776 filter_mode
|= FILESYS_FILTER
;
777 else if (!strcmp(optarg
, "cachehit"))
778 show_cachehits
= true;
779 else if (!strcmp(optarg
, "exec"))
780 filter_mode
|= EXEC_FILTER
;
781 else if (!strcmp(optarg
, "pathname"))
782 filter_mode
|= PATHNAME_FILTER
;
783 else if (!strcmp(optarg
, "diskio"))
784 filter_mode
|= DISKIO_FILTER
;
793 time_limit_ns
= (uint64_t)(NSEC_PER_SEC
* atof(optarg
));
794 if (time_limit_ns
== 0) {
795 fprintf(stderr
, "ERROR: could not set time limit to %s\n",
803 rv
= ktrace_set_file(s
, optarg
);
805 fprintf(stderr
, "ERROR: reading trace from '%s' failed (%s)\n", optarg
, strerror(errno
));
811 start_time_ns
= NSEC_PER_SEC
* atof(optarg
);
815 end_time_ns
= NSEC_PER_SEC
* atof(optarg
);
826 if (time_limit_ns
> 0 && RAW_flag
) {
827 fprintf(stderr
, "NOTE: time limit ignored when a raw file is specified\n");
832 if (geteuid() != 0) {
833 fprintf(stderr
, "'fs_usage' must be run as root...\n");
838 * ktrace can't both *in*clude and *ex*clude pids, so: if we are
839 * already excluding pids, or if we are not explicitly including
840 * or excluding any pids, then exclude the defaults.
842 * if on the other hand we are explicitly including pids, we'll
843 * filter the defaults out naturally.
845 if (exclude_pids
|| argc
== 0) {
846 ktrace_exclude_process(s
, "fs_usage");
847 ktrace_exclude_process(s
, "Terminal");
848 ktrace_exclude_process(s
, "telnetd");
849 ktrace_exclude_process(s
, "telnet");
850 ktrace_exclude_process(s
, "sshd");
851 ktrace_exclude_process(s
, "rlogind");
852 ktrace_exclude_process(s
, "tcsh");
853 ktrace_exclude_process(s
, "csh");
854 ktrace_exclude_process(s
, "sh");
855 ktrace_exclude_process(s
, "zsh");
856 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
857 ktrace_exclude_process(s
, "dropbear");
858 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
863 * If we're *in*cluding processes, also *in*clude the kernel_task, which
864 * issues trace points when disk I/Os complete. But set a flag for us to
865 * avoid showing events attributed to the kernel_task.
867 * If the user actually wants to those events, we'll change that flag in
870 if (argc
> 0 && !exclude_pids
) {
871 ktrace_filter_pid(s
, 0);
872 want_kernel_task
= false;
876 * Process the list of specified pids, and in/exclude them as
885 pid
= (pid_t
)strtoul(name
, &endptr
, 10);
887 if (*name
!= '\0' && *endptr
== '\0') {
889 rv
= ktrace_exclude_pid(s
, pid
);
892 want_kernel_task
= true;
894 rv
= ktrace_filter_pid(s
, pid
);
898 rv
= ktrace_exclude_process(s
, name
);
900 if (!strcmp(name
, "kernel_task"))
901 want_kernel_task
= true;
903 rv
= ktrace_filter_process(s
, name
);
908 fprintf(stderr
, "ERROR: cannot both include and exclude simultaneously\n");
918 /* provides SIGINT, SIGHUP, SIGPIPE, SIGTERM handlers */
919 ktrace_set_signal_handler(s
);
921 ktrace_set_completion_handler(s
, ^{
925 signal(SIGWINCH
, SIG_IGN
);
926 sigwinch_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL
, SIGWINCH
, 0, dispatch_get_main_queue());
927 dispatch_source_set_event_handler(sigwinch_source
, ^{
931 dispatch_activate(sigwinch_source
);
933 init_shared_cache_mapping();
937 setup_ktrace_callbacks();
939 ktrace_set_dropped_events_handler(s
, ^{
940 fprintf(stderr
, "fs_usage: buffer overrun, events generated too quickly\n");
942 /* clear any state that is now potentially invalid */
949 ktrace_set_default_event_names_enabled(KTRACE_FEATURE_DISABLED
);
950 ktrace_set_execnames_enabled(s
, KTRACE_FEATURE_LAZY
);
951 ktrace_set_vnode_paths_enabled(s
, true);
952 /* no need to symbolicate addresses */
953 ktrace_set_uuid_map_enabled(s
, KTRACE_FEATURE_DISABLED
);
955 rv
= ktrace_start(s
, dispatch_get_main_queue());
958 perror("ktrace_start");
962 if (time_limit_ns
> 0) {
963 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, time_limit_ns
),
964 dispatch_get_global_queue(QOS_CLASS_USER_INITIATED
, 0),
976 setup_ktrace_callbacks(void)
978 ktrace_events_subclass(s
, DBG_MACH
, DBG_MACH_EXCP_SC
, ^(ktrace_event_t event
) {
981 type
= event
->debugid
& KDBG_EVENTID_MASK
;
983 if (type
== MSC_map_fd
) {
984 if (event
->debugid
& DBG_FUNC_START
) {
985 event_enter(type
, event
);
987 event_exit("map_fd", type
, event
, FMT_FD
);
992 ktrace_events_subclass(s
, DBG_MACH
, DBG_MACH_VM
, ^(ktrace_event_t event
) {
996 type
= event
->debugid
& KDBG_EVENTID_MASK
;
998 if (type
!= MACH_pageout
&& type
!= MACH_vmfault
)
1001 if (event
->debugid
& DBG_FUNC_START
) {
1002 event_enter(type
, event
);
1007 event_exit("PAGE_OUT_ANON", type
, event
, FMT_PGOUT
);
1009 event_exit("PAGE_OUT_FILE", type
, event
, FMT_PGOUT
);
1014 if (event
->arg4
== DBG_PAGEIN_FAULT
)
1015 event_exit("PAGE_IN", type
, event
, FMT_PGIN
);
1016 else if (event
->arg4
== DBG_PAGEINV_FAULT
)
1017 event_exit("PAGE_IN_FILE", type
, event
, FMT_PGIN
);
1018 else if (event
->arg4
== DBG_PAGEIND_FAULT
)
1019 event_exit("PAGE_IN_ANON", type
, event
, FMT_PGIN
);
1020 else if (event
->arg4
== DBG_CACHE_HIT_FAULT
)
1021 event_exit("CACHE_HIT", type
, event
, FMT_CACHEHIT
);
1022 else if ((ti
= event_find(event
->threadid
, type
)))
1033 if (include_waited_flag
|| RAW_flag
) {
1034 ktrace_events_subclass(s
, DBG_MACH
, DBG_MACH_SCHED
, ^(ktrace_event_t event
) {
1037 type
= event
->debugid
& KDBG_EVENTID_MASK
;
1042 case MACH_stkhandoff
:
1043 event_mark_thread_waited(event
->threadid
);
1048 ktrace_events_subclass(s
, DBG_FSYSTEM
, DBG_FSRW
, ^(ktrace_event_t event
) {
1052 type
= event
->debugid
& KDBG_EVENTID_MASK
;
1055 case HFS_modify_block_end
:
1057 * the expected path here is as follows:
1059 * look up a path, which gets stored in ti->vnode / ti->pathname
1060 * modify a metadata block -- we assume the modification has something to do with the path that was looked up
1063 * later, someone writes that metadata block; the last path associated with it is attributed
1065 if ((ti
= event_find(event
->threadid
, 0))) {
1066 if (ti
->newest_pathname
)
1067 meta_add_name(event
->arg2
, ti
->newest_pathname
);
1073 if (event
->debugid
& DBG_FUNC_START
) {
1074 if ((ti
= event_find(event
->threadid
, 0)) && !ti
->vnodeid
) {
1075 ti
->vnodeid
= event
->arg1
;
1079 /* it can be both start and end */
1081 if (event
->debugid
& DBG_FUNC_END
) {
1082 if ((ti
= event_find(event
->threadid
, 0)) && ti
->vnodeid
) {
1083 const char *pathname
;
1085 pathname
= ktrace_get_path_for_vp(s
, ti
->vnodeid
);
1090 if (ti
->pathname
[0] == '\0') {
1091 strncpy(ti
->pathname
, pathname
, MAXPATHLEN
);
1092 ti
->newest_pathname
= ti
->pathname
;
1093 } else if (ti
->pathname2
[0] == '\0') {
1094 strncpy(ti
->pathname2
, pathname
, MAXPATHLEN
);
1095 ti
->newest_pathname
= ti
->pathname2
;
1104 if (type
!= Throttled
&& type
!= HFS_update
)
1107 if (event
->debugid
& DBG_FUNC_START
) {
1108 event_enter(type
, event
);
1112 event_exit(" THROTTLED", type
, event
, FMT_NOTHING
);
1116 event_exit(" HFS_update", type
, event
, FMT_HFS_update
);
1125 ktrace_events_subclass(s
, DBG_FSYSTEM
, DBG_DKRW
, ^(ktrace_event_t event
) {
1129 type
= event
->debugid
& KDBG_EVENTID_MASK
;
1131 if ((type
& P_DISKIO_MASK
) == P_DISKIO
) {
1132 diskio_start(type
, event
->arg1
, event
->arg2
, event
->arg3
, event
->arg4
, event
);
1133 } else if ((type
& P_DISKIO_MASK
) == P_DISKIO_DONE
) {
1134 if ((dio
= diskio_complete(event
->arg1
, event
->arg4
, event
->arg3
, event
->threadid
, event
->timestamp
, event
->walltime
))) {
1135 dio
->vnodeid
= event
->arg2
;
1142 ktrace_events_subclass(s
, DBG_FSYSTEM
, DBG_IOCTL
, ^(ktrace_event_t event
) {
1147 type
= event
->debugid
& KDBG_EVENTID_MASK
;
1150 case SPEC_unmap_info
:
1151 pid
= ktrace_get_pid_for_thread(s
, event
->threadid
);
1153 if (check_filter_mode(pid
, NULL
, SPEC_unmap_info
, 0, 0, "SPEC_unmap_info"))
1154 format_print(NULL
, " TrimExtent", event
, type
, FMT_UNMAP_INFO
, event
->timestamp
, event
->timestamp
, 0, "", NULL
);
1159 if (event
->debugid
& DBG_FUNC_START
) {
1160 event_enter(type
, event
);
1162 if (event
->arg2
== DKIOCSYNCHRONIZECACHE
)
1163 event_exit("IOCTL", type
, event
, FMT_IOCTL_SYNCCACHE
);
1164 else if (event
->arg2
== DKIOCUNMAP
)
1165 event_exit("IOCTL", type
, event
, FMT_IOCTL_UNMAP
);
1166 else if (event
->arg2
== DKIOCSYNCHRONIZE
&& (event
->debugid
& DBG_FUNC_ALL
) == DBG_FUNC_NONE
)
1167 event_exit("IOCTL", type
, event
, FMT_IOCTL_SYNC
);
1168 else if ((ti
= event_find(event
->threadid
, type
)))
1176 if (BC_flag
|| RAW_flag
) {
1177 ktrace_events_subclass(s
, DBG_FSYSTEM
, DBG_BOOTCACHE
, ^(ktrace_event_t event
) {
1181 type
= event
->debugid
& KDBG_EVENTID_MASK
;
1185 case BC_IO_HIT_STALLED
:
1187 case BC_IO_MISS_CUT_THROUGH
:
1188 case BC_PLAYBACK_IO
:
1189 if ((dio
= diskio_find(event
->arg1
)) != NULL
)
1190 dio
->bc_info
= type
;
1195 void (^bsd_sc_proc_cb
)(ktrace_event_t event
) = ^(ktrace_event_t event
) {
1199 type
= event
->debugid
& KDBG_EVENTID_MASK
;
1202 case BSC_exit
: /* see below */
1206 event
->arg1
= event
->arg2
>> 8;
1209 pid
= ktrace_get_pid_for_thread(s
, event
->threadid
);
1215 if (event
->arg4
& MAP_ANON
)
1221 if ((index
= BSC_INDEX(type
)) >= MAX_BSD_SYSCALL
)
1224 if (!bsd_syscalls
[index
].sc_name
)
1227 if (event
->debugid
& DBG_FUNC_START
) {
1228 event_enter(type
, event
);
1230 event_exit(bsd_syscalls
[index
].sc_name
, type
, event
, bsd_syscalls
[index
].sc_format
);
1234 ktrace_events_subclass(s
, DBG_BSD
, DBG_BSD_EXCP_SC
, bsd_sc_proc_cb
);
1235 ktrace_events_subclass(s
, DBG_BSD
, DBG_BSD_PROC
, bsd_sc_proc_cb
);
1237 ktrace_events_range(s
, KDBG_EVENTID(DBG_BSD
, DBG_BSD_SC_EXTENDED_INFO
, 0), KDBG_EVENTID(DBG_BSD
, DBG_BSD_SC_EXTENDED_INFO2
+ 1, 0), ^(ktrace_event_t event
) {
1238 extend_syscall(event
->threadid
, event
->debugid
& KDBG_EVENTID_MASK
, event
);
1241 ktrace_events_subclass(s
, DBG_CORESTORAGE
, DBG_CS_IO
, ^(ktrace_event_t event
) {
1242 // the usual DBG_FUNC_START/END does not work for i/o since it will
1243 // return on a different thread, this code uses the P_CS_IO_Done (0x4) bit
1244 // instead. the trace command doesn't know how handle either method
1245 // (unmatched start/end or 0x4) but works a little better this way.
1248 int cs_type
= event
->debugid
& P_CS_Type_Mask
; // strip out the done bit
1249 bool start
= (event
->debugid
& P_CS_IO_Done
) != P_CS_IO_Done
;
1252 case P_CS_ReadChunk
:
1253 case P_CS_WriteChunk
:
1255 case P_CS_MetaWrite
:
1257 diskio_start(cs_type
, event
->arg2
, event
->arg1
, event
->arg3
, event
->arg4
, event
);
1259 if ((dio
= diskio_complete(event
->arg2
, event
->arg4
, event
->arg3
, event
->threadid
, event
->timestamp
, event
->walltime
))) {
1266 case P_CS_TransformRead
:
1267 case P_CS_TransformWrite
:
1268 case P_CS_MigrationRead
:
1269 case P_CS_MigrationWrite
:
1271 diskio_start(cs_type
, event
->arg2
, CS_DEV
, event
->arg3
, event
->arg4
, event
);
1273 if ((dio
= diskio_complete(event
->arg2
, event
->arg4
, event
->arg3
, event
->threadid
, event
->timestamp
, event
->walltime
))) {
1283 ktrace_events_subclass(s
, DBG_CORESTORAGE
, 1 /* DBG_CS_SYNC */, ^(ktrace_event_t event
) {
1284 int cs_type
= event
->debugid
& P_CS_Type_Mask
; // strip out the done bit
1285 bool start
= (event
->debugid
& P_CS_IO_Done
) != P_CS_IO_Done
;
1287 if (cs_type
== P_CS_SYNC_DISK
) {
1289 event_enter(cs_type
, event
);
1291 event_exit(" SyncCacheCS", cs_type
, event
, FMT_SYNC_DISK_CS
);
1298 extend_syscall_rw(th_info_t ti
, ktrace_event_t event
)
1300 ti
->arg1
= event
->arg1
; /* the fd */
1301 ti
->arg2
= event
->arg2
; /* nbytes */
1302 ti
->arg3
= event
->arg3
; /* top half offset */
1303 ti
->arg4
= event
->arg4
; /* bottom half offset */
1307 * Handle system call extended trace data.
1309 * Wipe out the kd args that were collected upon syscall_entry
1310 * because it is the extended info that we really want, and it
1311 * is all we really need.
1314 extend_syscall(uint64_t thread
, int type
, ktrace_event_t event
)
1319 case BSC_mmap_extended
:
1320 if ((ti
= event_find(thread
, BSC_mmap
)) == NULL
) {
1324 ti
->arg8
= ti
->arg3
; /* save protection */
1325 ti
->arg1
= event
->arg1
; /* the fd */
1326 ti
->arg3
= event
->arg2
; /* bottom half address */
1327 ti
->arg5
= event
->arg3
; /* bottom half size */
1330 case BSC_mmap_extended2
:
1331 if ((ti
= event_find(thread
, BSC_mmap
)) == NULL
)
1334 ti
->arg2
= event
->arg1
; /* top half address */
1335 ti
->arg4
= event
->arg2
; /* top half size */
1336 ti
->arg6
= event
->arg3
; /* top half file offset */
1337 ti
->arg7
= event
->arg4
; /* bottom half file offset */
1340 case BSC_msync_extended
:
1341 if ((ti
= event_find(thread
, BSC_msync
)) == NULL
) {
1342 if ((ti
= event_find(thread
, BSC_msync_nocancel
)) == NULL
) {
1347 ti
->arg4
= event
->arg1
; /* top half address */
1348 ti
->arg5
= event
->arg2
; /* top half size */
1351 case BSC_pread_extended
:
1352 if ((ti
= event_find(thread
, BSC_pread
)) == NULL
) {
1353 if ((ti
= event_find(thread
, BSC_pread_nocancel
)) == NULL
) {
1358 extend_syscall_rw(ti
, event
);
1361 case BSC_pwrite_extended
:
1362 if ((ti
= event_find(thread
, BSC_pwrite
)) == NULL
) {
1363 if ((ti
= event_find(thread
, BSC_pwrite_nocancel
)) == NULL
) {
1368 extend_syscall_rw(ti
, event
);
1371 case BSC_guarded_pwrite_extended
:
1372 if ((ti
= event_find(thread
, BSC_guarded_pwrite_np
)) == NULL
) {
1376 extend_syscall_rw(ti
, event
);
1381 #pragma mark printing routines
1384 get_mode_nibble(char *buf
, uint64_t smode
, uint64_t special
, char x_on
, char x_off
)
1404 get_mode_string(uint64_t mode
, char *buf
)
1406 memset(buf
, '-', 9);
1409 get_mode_nibble(&buf
[6], mode
, (mode
& 01000), 't', 'T');
1410 get_mode_nibble(&buf
[3], (mode
>>3), (mode
& 02000), 's', 'S');
1411 get_mode_nibble(&buf
[0], (mode
>>6), (mode
& 04000), 's', 'S');
1415 clip_64bit(char *s
, uint64_t value
)
1419 if ( (value
& 0xff00000000000000LL
) )
1420 clen
= printf("%s0x%16.16qx", s
, value
);
1421 else if ( (value
& 0x00ff000000000000LL
) )
1422 clen
= printf("%s0x%14.14qx ", s
, value
);
1423 else if ( (value
& 0x0000ff0000000000LL
) )
1424 clen
= printf("%s0x%12.12qx ", s
, value
);
1425 else if ( (value
& 0x000000ff00000000LL
) )
1426 clen
= printf("%s0x%10.10qx ", s
, value
);
1428 clen
= printf("%s0x%8.8qx ", s
, value
);
1434 * ret = 1 means print the entry
1435 * ret = 0 means don't print the entry
1439 * meaning of filter flags:
1440 * cachehit turn on display of CACHE_HIT events (which are filtered out by default)
1442 * exec show exec/posix_spawn
1443 * pathname show events with a pathname and close()
1444 * diskio show disk I/Os
1445 * filesys show filesystem events
1446 * network show network events
1448 * filters may be combined; default is all filters on (except cachehit)
1451 check_filter_mode(pid_t pid
, th_info_t ti
, uint64_t type
, int error
, int retval
, char *sc_name
)
1454 int network_fd_isset
= 0;
1457 /* cachehit is special -- it's not on by default */
1458 if (sc_name
[0] == 'C' && !strcmp(sc_name
, "CACHE_HIT")) {
1459 return show_cachehits
;
1462 if (filter_mode
== DEFAULT_DO_NOT_FILTER
)
1465 if (filter_mode
& DISKIO_FILTER
) {
1466 if ((type
& P_DISKIO_MASK
) == P_DISKIO
)
1469 if (type
== Throttled
)
1473 if (filter_mode
& EXEC_FILTER
) {
1474 if (type
== BSC_execve
|| type
== BSC_posix_spawn
)
1478 if (filter_mode
& PATHNAME_FILTER
) {
1479 if (ti
&& ti
->pathname
[0])
1482 if (type
== BSC_close
|| type
== BSC_close_nocancel
||
1483 type
== BSC_guarded_close_np
)
1488 if (filter_mode
& FILESYS_FILTER
)
1496 case BSC_close_nocancel
:
1497 case BSC_guarded_close_np
:
1499 network_fd_isset
= fd_is_network(pid
, fd
);
1502 fd_set_is_network(pid
, fd
, false);
1504 if (network_fd_isset
) {
1505 if (filter_mode
& NETWORK_FILTER
)
1508 if (filter_mode
& FILESYS_FILTER
)
1516 case BSC_read_nocancel
:
1517 case BSC_write_nocancel
:
1519 * we don't care about error in these cases
1523 if (fd_is_network(pid
, fd
)) {
1524 if (filter_mode
& NETWORK_FILTER
)
1526 } else if (filter_mode
& FILESYS_FILTER
) {
1533 case BSC_accept_nocancel
:
1538 fd_set_is_network(pid
, fd
, true);
1540 if (filter_mode
& NETWORK_FILTER
)
1552 case BSC_sendto_nocancel
:
1553 case BSC_recvfrom_nocancel
:
1554 case BSC_recvmsg_nocancel
:
1555 case BSC_sendmsg_nocancel
:
1556 case BSC_connect_nocancel
:
1560 fd_set_is_network(pid
, fd
, true);
1562 if (filter_mode
& NETWORK_FILTER
)
1568 case BSC_select_nocancel
:
1569 case BSC_socketpair
:
1571 * Cannot determine info about file descriptors
1573 if (filter_mode
& NETWORK_FILTER
)
1581 * We track these cases for fd state only
1585 if (error
== 0 && fd_is_network(pid
, fd
)) {
1587 * then we are duping a socket descriptor
1589 fd
= retval
; /* the new fd */
1590 fd_set_is_network(pid
, fd
, true);
1596 if (filter_mode
& FILESYS_FILTER
)
1606 print_open(ktrace_event_t event
, uint64_t flags
)
1611 (flags
& O_CREAT
) ? 'C' : '_',
1612 (flags
& O_APPEND
) ? 'A' : '_',
1613 (flags
& O_TRUNC
) ? 'T' : '_',
1614 (flags
& O_EXCL
) ? 'E' : '_',
1615 (flags
& O_NONBLOCK
) ? 'N' : '_',
1616 (flags
& O_SHLOCK
) ? 'l' : (flags
& O_EXLOCK
) ? 'L' : '_',
1617 (flags
& O_NOFOLLOW
) ? 'F' : '_',
1618 (flags
& O_SYMLINK
) ? 'S' : '_',
1619 (flags
& O_EVTONLY
) ? 'V' : '_',
1620 (flags
& O_CLOEXEC
) ? 'X' : '_',
1624 if (flags
& O_RDWR
) {
1627 } else if (flags
& O_WRONLY
) {
1634 return printf(" [%3d] (%s) ", (int)event
->arg1
, mode
);
1636 return printf(" F=%-3d (%s) ", (int)event
->arg2
, mode
);
1643 * exit_event() (syscalls etc.)
1644 * print_diskio() (disk I/Os)
1645 * block callback for TrimExtent
1648 format_print(th_info_t ti
, char *sc_name
, ktrace_event_t event
,
1649 uint64_t type
, int format
, uint64_t now
, uint64_t stime
,
1650 int waited
, const char *pathname
, struct diskio
*dio
)
1652 uint64_t secs
, usecs
;
1654 static time_t last_walltime_secs
= -1;
1655 const char *command_name
;
1663 char *framework_name
;
1664 char *framework_type
;
1667 char buf
[2 * PATH_MAX
+ 64];
1668 char cs_diskname
[32];
1670 struct timeval now_walltime
;
1672 static char timestamp
[32];
1673 static size_t timestamp_len
= 0;
1675 if (!mach_time_of_first_event
)
1676 mach_time_of_first_event
= now
;
1678 if (format
== FMT_DISKIO
|| format
== FMT_DISKIO_CS
) {
1683 if (format
!= FMT_UNMAP_INFO
)
1687 /* <rdar://problem/19852325> Filter out WindowServer/xcpm ioctls in fs_usage */
1688 if (type
== BSC_ioctl
&& ti
->arg2
== 0xffffffffc030581dUL
)
1691 /* honor -S and -E */
1693 uint64_t relative_time_ns
;
1695 relative_time_ns
= mach_to_nano(now
- mach_time_of_first_event
);
1697 if (relative_time_ns
< start_time_ns
|| relative_time_ns
> end_time_ns
)
1701 class = KDBG_EXTRACT_CLASS(type
);
1704 command_name
= dio
->issuing_command
;
1705 threadid
= dio
->issuing_thread
;
1706 pid
= dio
->issuing_pid
;
1707 now_walltime
= dio
->completed_walltime
;
1709 if (ti
&& ti
->command
[0] != '\0') {
1710 command_name
= ti
->command
;
1711 threadid
= ti
->thread
;
1714 command_name
= ktrace_get_execname_for_thread(s
, event
->threadid
);
1715 threadid
= event
->threadid
;
1716 pid
= ktrace_get_pid_for_thread(s
, event
->threadid
);
1719 now_walltime
= event
->walltime
;
1722 if (!want_kernel_task
&& pid
== 0)
1728 os_assert(now_walltime
.tv_sec
|| now_walltime
.tv_usec
);
1730 /* try and reuse the timestamp string */
1731 if (last_walltime_secs
!= now_walltime
.tv_sec
) {
1732 timestamp_len
= strftime(timestamp
, sizeof (timestamp
), "%H:%M:%S", localtime(&now_walltime
.tv_sec
));
1733 last_walltime_secs
= now_walltime
.tv_sec
;
1736 if (columns
> MAXCOLS
|| wideflag
) {
1737 tlen
= timestamp_len
;
1740 sprintf(×tamp
[tlen
], ".%06d", now_walltime
.tv_usec
);
1743 timestamp
[tlen
] = '\0';
1748 clen
= printf("%s %-17.17s", timestamp
, sc_name
);
1750 framework_name
= NULL
;
1752 if (columns
> MAXCOLS
|| wideflag
) {
1753 off_t offset_reassembled
= 0LL;
1757 clen
+= printf(" ");
1764 * pathname based system calls or
1765 * calls with no fd or pathname (i.e. sync)
1768 clen
+= printf(" [%3d] ", (int)event
->arg1
);
1770 clen
+= printf(" ");
1776 * fd based system call... no I/O
1779 clen
+= printf(" F=%-3d[%3d]", (int)ti
->arg1
, (int)event
->arg1
);
1781 clen
+= printf(" F=%-3d", (int)ti
->arg1
);
1790 clen
+= printf(" F=%-3d[%3d]", (int)ti
->arg1
, (int)event
->arg1
);
1792 clen
+= printf(" F=%-3d F=%-3d", (int)ti
->arg1
, (int)event
->arg2
);
1798 * system calls with fd's that return an I/O completion count
1801 clen
+= printf(" F=%-3d[%3d]", (int)ti
->arg1
, (int)event
->arg1
);
1803 clen
+= printf(" F=%-3d B=0x%-6" PRIx64
, (int)ti
->arg1
, (uint64_t)event
->arg2
);
1811 user_addr
= ((uint64_t)event
->arg1
<< 32) | (uint32_t)event
->arg2
;
1813 lookup_name(user_addr
, &framework_type
, &framework_name
);
1814 clen
+= clip_64bit(" A=", user_addr
);
1821 user_addr
= ((uint64_t)event
->arg1
<< 32) | (uint32_t)event
->arg2
;
1823 lookup_name(user_addr
, &framework_type
, &framework_name
);
1824 clen
+= clip_64bit(" A=", user_addr
);
1831 clen
+= printf(" B=0x%-8" PRIx64
, (uint64_t)event
->arg1
);
1834 case FMT_HFS_update
:
1836 static const struct {
1840 { DBG_HFS_UPDATE_SKIPPED
, 'S' },
1841 { DBG_HFS_UPDATE_FORCE
, 'F' },
1842 { DBG_HFS_UPDATE_MODIFIED
, 'M' },
1843 { DBG_HFS_UPDATE_MINOR
, 'N' },
1844 { DBG_HFS_UPDATE_DATEADDED
, 'd' },
1845 { DBG_HFS_UPDATE_CHGTIME
, 'c' },
1846 { DBG_HFS_UPDATE_ACCTIME
, 'a' },
1847 { DBG_HFS_UPDATE_MODTIME
, 'm' },
1852 int sflag
= (int)event
->arg2
;
1854 flagcount
= sizeof (hfsflags
) / sizeof (*hfsflags
);
1855 sbuf
= malloc(flagcount
+ 1);
1857 for (i
= 0; i
< flagcount
; i
++) {
1858 if (sflag
& hfsflags
[i
].flag
) {
1859 sbuf
[i
] = hfsflags
[i
].ch
;
1865 sbuf
[flagcount
] = '\0';
1867 clen
+= printf(" %*s(%s) ", 17 - flagcount
, "", sbuf
);
1871 pathname
= ktrace_get_path_for_vp(s
, event
->arg1
);
1885 if (dio
->io_errno
) {
1886 clen
+= printf(" D=0x%8.8" PRIx64
" [%3d]", dio
->blkno
, (int)dio
->io_errno
);
1889 clen
+= printf(" D=0x%8.8" PRIx64
" B=0x%-6" PRIx64
" BC:%s /dev/%s ", dio
->blkno
, dio
->iosize
, BC_STR(dio
->bc_info
), find_disk_name(dio
->dev
));
1891 clen
+= printf(" D=0x%8.8" PRIx64
" B=0x%-6" PRIx64
" /dev/%s ", dio
->blkno
, dio
->iosize
, find_disk_name(dio
->dev
));
1894 if (!(type
& P_DISKIO_READ
)) {
1895 pathname
= meta_find_name(dio
->blkno
);
1898 pathname
= ktrace_get_path_for_vp(s
, dio
->vnodeid
);
1914 clen
+= printf(" D=0x%8.8" PRIx64
" [%3" PRIu64
"]", dio
->blkno
, dio
->io_errno
);
1916 clen
+= printf(" D=0x%8.8" PRIx64
" B=0x%-6" PRIx64
" /dev/%s", dio
->blkno
, dio
->iosize
, generate_cs_disk_name(dio
->dev
, cs_diskname
));
1920 case FMT_SYNC_DISK_CS
:
1922 * physical disk sync cache
1924 clen
+= printf(" /dev/%s", generate_cs_disk_name(event
->arg1
, cs_diskname
));
1937 if (ti
->arg3
& MS_ASYNC
)
1938 mlen
+= sprintf(&buf
[mlen
], "MS_ASYNC | ");
1940 mlen
+= sprintf(&buf
[mlen
], "MS_SYNC | ");
1942 if (ti
->arg3
& MS_INVALIDATE
)
1943 mlen
+= sprintf(&buf
[mlen
], "MS_INVALIDATE | ");
1944 if (ti
->arg3
& MS_KILLPAGES
)
1945 mlen
+= sprintf(&buf
[mlen
], "MS_KILLPAGES | ");
1946 if (ti
->arg3
& MS_DEACTIVATE
)
1947 mlen
+= sprintf(&buf
[mlen
], "MS_DEACTIVATE | ");
1949 if (ti
->arg3
& ~(MS_ASYNC
| MS_SYNC
| MS_INVALIDATE
| MS_KILLPAGES
| MS_DEACTIVATE
))
1950 mlen
+= sprintf(&buf
[mlen
], "UNKNOWN | ");
1953 buf
[mlen
- 3] = '\0';
1956 clen
+= printf(" [%3d]", (int)event
->arg1
);
1958 user_addr
= (((off_t
)(unsigned int)(ti
->arg4
)) << 32) | (unsigned int)(ti
->arg1
);
1959 clen
+= clip_64bit(" A=", user_addr
);
1961 user_size
= (((off_t
)(unsigned int)(ti
->arg5
)) << 32) | (unsigned int)(ti
->arg2
);
1963 clen
+= printf(" B=0x%-16qx <%s>", user_size
, buf
);
1977 if (ti
->arg2
& LOCK_SH
)
1978 mlen
+= sprintf(&buf
[mlen
], "LOCK_SH | ");
1979 if (ti
->arg2
& LOCK_EX
)
1980 mlen
+= sprintf(&buf
[mlen
], "LOCK_EX | ");
1981 if (ti
->arg2
& LOCK_NB
)
1982 mlen
+= sprintf(&buf
[mlen
], "LOCK_NB | ");
1983 if (ti
->arg2
& LOCK_UN
)
1984 mlen
+= sprintf(&buf
[mlen
], "LOCK_UN | ");
1986 if (ti
->arg2
& ~(LOCK_SH
| LOCK_EX
| LOCK_NB
| LOCK_UN
))
1987 mlen
+= sprintf(&buf
[mlen
], "UNKNOWN | ");
1990 buf
[mlen
- 3] = '\0';
1993 clen
+= printf(" F=%-3d[%3d] <%s>", (int)ti
->arg1
, (int)event
->arg1
, buf
);
1995 clen
+= printf(" F=%-3d <%s>", (int)ti
->arg1
, buf
);
2009 clen
+= printf(" F=%-3d[%3d]", (int)ti
->arg1
, (int)event
->arg1
);
2011 clen
+= printf(" F=%-3d", (int)ti
->arg1
);
2054 case F_SETLKWTIMEOUT
:
2055 p
= "SETLKWTIMEOUT";
2074 case F_OFD_SETLKWTIMEOUT
:
2075 p
= "OFD_SETLKWTIMEOUT";
2078 case F_OFD_GETLKPID
:
2102 case F_PATHPKG_CHECK
:
2103 p
= "PATHPKG_CHECK";
2109 if (event
->arg1
== 0)
2110 fd
= (int)event
->arg2
;
2117 case F_CHECK_OPENEVT
:
2118 p
= "CHECK_OPENEVT";
2128 case F_GLOBAL_NOCACHE
:
2130 p
= "CACHING OFF (GLOBAL)";
2132 p
= "CACHING ON (GLOBAL)";
2167 case F_MARKDEPENDENCY
:
2168 p
= "MARKDEPENDENCY";
2179 case F_GETPROTECTIONCLASS
:
2180 p
= "GETPROTECTIONCLASS";
2183 case F_SETPROTECTIONCLASS
:
2184 p
= "SETPROTECTIONCLASS";
2187 case F_LOG2PHYS_EXT
:
2191 case F_SETSTATICCONTENT
:
2193 p
= "STATICCONTENT ON";
2195 p
= "STATICCONTENT OFF";
2199 case F_MOVEDATAEXTENTS
:
2200 p
= "MOVEDATAEXTENTS";
2203 case F_DUPFD_CLOEXEC
:
2204 p
= "DUPFD_CLOEXEC";
2207 case F_SETBACKINGSTORE
:
2208 p
= "SETBACKINGSTORE";
2211 case F_GETPATH_MTMINFO
:
2212 p
= "GETPATH_MTMINFO";
2219 case F_SETNOSIGPIPE
:
2223 case F_GETNOSIGPIPE
:
2227 case F_TRANSCODEKEY
:
2231 case F_SINGLE_WRITER
:
2232 p
= "SINGLE_WRITER";
2235 case F_GETPROTECTIONLEVEL
:
2236 p
= "GETPROTECTIONLEVEL";
2243 case F_GETDEFAULTPROTLEVEL
:
2244 p
= "GETDEFAULTPROTLEVEL";
2247 case F_MAKECOMPRESSED
:
2248 p
= "MAKECOMPRESSED";
2251 case F_SET_GREEDY_MODE
:
2253 p
= "GREEDY_MODE ON";
2255 p
= "GREEDY_MODE OFF";
2263 case F_ADDFILESIGS_FOR_DYLD_SIM
:
2264 p
= "ADDFILESIGS_FOR_DYLD_SIM";
2271 case F_BARRIERFSYNC
:
2283 case F_ADDFILESIGS_RETURN
:
2284 p
= "ADDFILESIGS_RETURN";
2295 case F_TRIM_ACTIVE_FILE
:
2296 p
= "TRIM_ACTIVE_FILE";
2299 case F_SPECULATIVE_READ
:
2300 p
= "SPECULATIVE_READ";
2303 case F_GETPATH_NOFIRMLINK
:
2304 p
= "GETPATH_NOFIRMLINK";
2307 case F_ADDFILESIGS_INFO
:
2308 p
= "ADDFILESIGS_INFO";
2311 case F_ADDFILESUPPL
:
2315 #ifdef F_GETSIGSINFO
2319 #endif // F_GETSIGSINFO
2324 clen
+= printf(" <%s>", p
);
2326 clen
+= printf(" <%s> F=%d", p
, fd
);
2328 clen
+= printf(" <CMD=%d>", (int)ti
->arg2
);
2340 clen
+= printf(" F=%-3d[%3d]", (int)ti
->arg1
, (int)event
->arg1
);
2342 clen
+= printf(" F=%-3d", (int)ti
->arg1
);
2344 clen
+= printf(" <CMD=0x%x>", (int)ti
->arg2
);
2349 case FMT_IOCTL_SYNC
:
2354 clen
+= printf(" <DKIOCSYNCHRONIZE> B=%" PRIu64
" /dev/%s", (uint64_t)event
->arg3
, find_disk_name(event
->arg1
));
2359 case FMT_IOCTL_SYNCCACHE
:
2364 clen
+= printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(event
->arg1
));
2369 case FMT_IOCTL_UNMAP
:
2374 clen
+= printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(event
->arg1
));
2379 case FMT_UNMAP_INFO
:
2381 clen
+= printf(" D=0x%8.8" PRIx64
" B=0x%-6" PRIx64
" /dev/%s", (uint64_t)event
->arg2
, (uint64_t)event
->arg3
, find_disk_name(event
->arg1
));
2391 clen
+= printf(" [%3d]", (int)event
->arg1
);
2393 clen
+= printf(" S=%-3d", (int)event
->arg2
);
2400 * pread, pwrite, lseek
2402 clen
+= printf(" F=%-3d", (int)ti
->arg1
);
2405 clen
+= printf("[%3d] ", (int)event
->arg1
);
2407 if (format
== FMT_PREAD
)
2408 clen
+= printf(" B=0x%-8" PRIx64
" ", (uint64_t)event
->arg2
);
2410 clen
+= printf(" ");
2413 if (format
== FMT_PREAD
)
2414 offset_reassembled
= (((off_t
)(unsigned int)(ti
->arg3
)) << 32) | (unsigned int)(ti
->arg4
);
2417 offset_reassembled
= (((off_t
)(unsigned int)(arg2
)) << 32) | (unsigned int)(arg3
);
2419 offset_reassembled
= (((off_t
)(unsigned int)(event
->arg3
)) << 32) | (unsigned int)(event
->arg2
);
2422 clen
+= clip_64bit("O=", offset_reassembled
);
2424 if (format
== FMT_LSEEK
) {
2427 if (ti
->arg3
== SEEK_SET
)
2429 else if (ti
->arg3
== SEEK_CUR
)
2431 else if (ti
->arg3
== SEEK_END
)
2436 clen
+= printf(" <%s>", mode
);
2445 clen
+= printf(" F=%-3d ", (int)ti
->arg1
);
2448 clen
+= printf("[%3d] ", (int)event
->arg1
);
2450 user_addr
= (((off_t
)(unsigned int)(ti
->arg2
)) << 32) | (unsigned int)(ti
->arg3
);
2452 clen
+= clip_64bit("A=", user_addr
);
2454 offset_reassembled
= (((off_t
)(unsigned int)(ti
->arg6
)) << 32) | (unsigned int)(ti
->arg7
);
2456 clen
+= clip_64bit("O=", offset_reassembled
);
2458 user_size
= (((off_t
)(unsigned int)(ti
->arg4
)) << 32) | (unsigned int)(ti
->arg5
);
2460 clen
+= printf("B=0x%-16qx", user_size
);
2462 clen
+= printf(" <");
2464 if (ti
->arg8
& PROT_READ
)
2465 clen
+= printf("READ");
2467 if (ti
->arg8
& PROT_WRITE
)
2468 clen
+= printf("|WRITE");
2470 if (ti
->arg8
& PROT_EXEC
)
2471 clen
+= printf("|EXEC");
2473 clen
+= printf(">");
2481 * ftruncate, truncate
2483 if (format
== FMT_FTRUNC
)
2484 clen
+= printf(" F=%-3d", (int)ti
->arg1
);
2486 clen
+= printf(" ");
2489 clen
+= printf("[%3d]", (int)event
->arg1
);
2492 offset_reassembled
= (((off_t
)(unsigned int)(ti
->arg2
)) << 32) | (unsigned int)(ti
->arg3
);
2494 offset_reassembled
= (((off_t
)(unsigned int)(ti
->arg3
)) << 32) | (unsigned int)(ti
->arg2
);
2496 clen
+= clip_64bit(" O=", offset_reassembled
);
2509 if (format
== FMT_FCHFLAGS
) {
2511 clen
+= printf(" F=%-3d[%3d]", (int)ti
->arg1
, (int)event
->arg1
);
2513 clen
+= printf(" F=%-3d", (int)ti
->arg1
);
2516 clen
+= printf(" [%3d] ", (int)event
->arg1
);
2522 if (ti
->arg2
& UF_NODUMP
)
2523 mlen
+= sprintf(&buf
[mlen
], "UF_NODUMP | ");
2524 if (ti
->arg2
& UF_IMMUTABLE
)
2525 mlen
+= sprintf(&buf
[mlen
], "UF_IMMUTABLE | ");
2526 if (ti
->arg2
& UF_APPEND
)
2527 mlen
+= sprintf(&buf
[mlen
], "UF_APPEND | ");
2528 if (ti
->arg2
& UF_OPAQUE
)
2529 mlen
+= sprintf(&buf
[mlen
], "UF_OPAQUE | ");
2530 if (ti
->arg2
& SF_ARCHIVED
)
2531 mlen
+= sprintf(&buf
[mlen
], "SF_ARCHIVED | ");
2532 if (ti
->arg2
& SF_IMMUTABLE
)
2533 mlen
+= sprintf(&buf
[mlen
], "SF_IMMUTABLE | ");
2534 if (ti
->arg2
& SF_APPEND
)
2535 mlen
+= sprintf(&buf
[mlen
], "SF_APPEND | ");
2538 mlen
+= sprintf(&buf
[mlen
], "CLEAR_ALL_FLAGS | ");
2539 else if (ti
->arg2
& ~(UF_NODUMP
| UF_IMMUTABLE
| UF_APPEND
| SF_ARCHIVED
| SF_IMMUTABLE
| SF_APPEND
))
2540 mlen
+= sprintf(&buf
[mlen
], "UNKNOWN | ");
2549 memset(&buf
[mlen
], ' ', 19 - mlen
);
2554 clen
+= printf("%s", buf
);
2562 case FMT_FCHMOD_EXT
:
2568 * fchmod, fchmod_extended, chmod, chmod_extended
2572 if (format
== FMT_FCHMOD
|| format
== FMT_FCHMOD_EXT
) {
2574 clen
+= printf(" F=%-3d[%3d] ", (int)ti
->arg1
, (int)event
->arg1
);
2576 clen
+= printf(" F=%-3d ", (int)ti
->arg1
);
2579 clen
+= printf(" [%3d] ", (int)event
->arg1
);
2581 clen
+= printf(" ");
2584 if (format
== FMT_UMASK
)
2586 else if (format
== FMT_FCHMOD
|| format
== FMT_CHMOD
|| format
== FMT_CHMODAT
)
2591 get_mode_string(mode
, &buf
[0]);
2593 if (event
->arg1
== 0)
2594 clen
+= printf("<%s> ", buf
);
2596 clen
+= printf("<%s>", buf
);
2607 memset(mode
, '_', 4);
2610 if (ti
->arg2
& R_OK
)
2612 if (ti
->arg2
& W_OK
)
2614 if (ti
->arg2
& X_OK
)
2616 if (ti
->arg2
== F_OK
)
2620 clen
+= printf(" [%3d] (%s) ", (int)event
->arg1
, mode
);
2622 clen
+= printf(" (%s) ", mode
);
2631 clen
+= printf(" [%3d] <FLGS=0x%" PRIx64
"> ", (int)event
->arg1
, ti
->arg3
);
2633 clen
+= printf(" <FLGS=0x%" PRIx64
"> ", ti
->arg3
);
2643 if (ti
->arg2
& MNT_FORCE
)
2644 mountflag
= "<FORCE>";
2649 clen
+= printf(" [%3d] %s ", (int)event
->arg1
, mountflag
);
2651 clen
+= printf(" %s ", mountflag
);
2658 clen
+= print_open(event
, ti
->arg2
);
2663 clen
+= print_open(event
, ti
->arg3
);
2667 case FMT_GUARDED_OPEN
:
2668 clen
+= print_open(event
, ti
->arg4
);
2699 domain
= "AF_IMPLINK";
2709 type
= "SOCK_STREAM";
2712 type
= "SOCK_DGRAM";
2723 clen
+= printf(" [%3d] <%s, %s, 0x%" PRIx64
">", (int)event
->arg1
, domain
, type
, ti
->arg3
);
2725 clen
+= printf(" F=%-3d <%s, %s, 0x%" PRIx64
">", (int)event
->arg2
, domain
, type
, ti
->arg3
);
2733 * aio_fsync [errno] AIOCBP OP
2737 if (ti
->arg1
== O_SYNC
|| ti
->arg1
== 0)
2740 else if (ti
->arg1
== O_DSYNC
)
2747 clen
+= printf(" [%3d] P=0x%8.8" PRIx64
" <%s>", (int)event
->arg1
, ti
->arg2
, op
);
2749 clen
+= printf(" P=0x%8.8" PRIx64
" <%s>", ti
->arg2
, op
);
2754 case FMT_AIO_RETURN
:
2756 * aio_return [errno] AIOCBP IOSIZE
2759 clen
+= printf(" [%3d] P=0x%8.8" PRIx64
, (int)event
->arg1
, ti
->arg1
);
2761 clen
+= printf(" P=0x%8.8" PRIx64
" B=0x%-8" PRIx64
, ti
->arg1
, (uint64_t)event
->arg2
);
2765 case FMT_AIO_SUSPEND
:
2767 * aio_suspend [errno] NENTS
2770 clen
+= printf(" [%3d] N=%d", (int)event
->arg1
, (int)ti
->arg2
);
2772 clen
+= printf(" N=%d", (int)ti
->arg2
);
2776 case FMT_AIO_CANCEL
:
2778 * aio_cancel [errno] FD or AIOCBP (if non-null)
2782 clen
+= printf(" [%3d] P=0x%8." PRIx64
, (int)event
->arg1
, ti
->arg2
);
2784 clen
+= printf(" P=0x%8.8" PRIx64
, ti
->arg2
);
2787 clen
+= printf(" F=%-3d[%3d]", (int)ti
->arg1
, (int)event
->arg1
);
2789 clen
+= printf(" F=%-3d", (int)ti
->arg1
);
2796 * aio_error, aio_read, aio_write [errno] AIOCBP
2799 clen
+= printf(" [%3d] P=0x%8.8" PRIx64
, (int)event
->arg1
, ti
->arg1
);
2801 clen
+= printf(" P=0x%8.8" PRIx64
, ti
->arg1
);
2805 case FMT_LIO_LISTIO
: {
2807 * lio_listio [errno] NENTS MODE
2811 if (ti
->arg1
== LIO_NOWAIT
)
2813 else if (ti
->arg1
== LIO_WAIT
)
2819 clen
+= printf(" [%3d] N=%d <%s>", (int)event
->arg1
, (int)ti
->arg3
, op
);
2821 clen
+= printf(" N=%d <%s>", (int)ti
->arg3
, op
);
2829 * Calculate space available to print pathname
2831 if (columns
> MAXCOLS
|| wideflag
)
2832 clen
= columns
- (clen
+ 14 + 20 + 11);
2834 clen
= columns
- (clen
+ 14 + 12);
2839 if (framework_name
) {
2840 len
= sprintf(&buf
[0], " %s %s ", framework_type
, framework_name
);
2841 } else if (*pathname
!= '\0') {
2846 len
= sprintf(&buf
[0], " [%d]/%s ", (int)ti
->arg1
, pathname
);
2849 len
= sprintf(&buf
[0], " [%d]/%s ", (int)ti
->arg3
, pathname
);
2852 len
= sprintf(&buf
[0], " %s ", pathname
);
2855 if (format
== FMT_MOUNT
&& ti
->pathname2
[0] != '\0') {
2858 memset(&buf
[len
], ' ', 2);
2860 len2
= sprintf(&buf
[len
+2], " %s ", ti
->pathname2
);
2861 len
= len
+ 2 + len2
;
2869 * Add null padding if column length
2870 * is wider than the pathname length.
2872 memset(&buf
[len
], ' ', clen
- len
);
2876 } else if (clen
== len
) {
2878 } else if ((clen
> 0) && (clen
< len
)) {
2880 * This prints the tail end of the pathname
2882 buf
[len
-clen
] = ' ';
2884 pathname
= &buf
[len
- clen
];
2890 * fudge some additional system call overhead
2891 * that currently isn't tracked... this also
2892 * insures that we see a minimum of 1 us for
2895 usecs
= (mach_to_nano(now
- stime
) + (NSEC_PER_USEC
- 1)) / NSEC_PER_USEC
;
2896 secs
= usecs
/ USEC_PER_SEC
;
2897 usecs
-= secs
* USEC_PER_SEC
;
2909 if (columns
> MAXCOLS
|| wideflag
)
2910 printf("%s%s %3llu.%06llu%s %s.%" PRIu64
"\n", p1
, pathname
, secs
, usecs
, p2
, command_name
, threadid
);
2912 printf("%s%s %3llu.%06llu%s %-12.12s\n", p1
, pathname
, secs
, usecs
, p2
, command_name
);
2918 #pragma mark metadata info hash routines
2920 #define VN_HASH_SIZE 16384
2921 #define VN_HASH_MASK (VN_HASH_SIZE - 1)
2923 typedef struct meta_info
{
2924 struct meta_info
*m_next
;
2926 char m_name
[MAXPATHLEN
];
2929 meta_info_t m_info_hash
[VN_HASH_SIZE
];
2932 meta_add_name(uint64_t blockno
, const char *pathname
)
2937 hashid
= blockno
& VN_HASH_MASK
;
2939 for (mi
= m_info_hash
[hashid
]; mi
; mi
= mi
->m_next
) {
2940 if (mi
->m_blkno
== blockno
)
2945 mi
= malloc(sizeof (struct meta_info
));
2947 mi
->m_next
= m_info_hash
[hashid
];
2948 m_info_hash
[hashid
] = mi
;
2949 mi
->m_blkno
= blockno
;
2952 strncpy(mi
->m_name
, pathname
, sizeof (mi
->m_name
));
2956 meta_find_name(uint64_t blockno
)
2961 hashid
= blockno
& VN_HASH_MASK
;
2963 for (mi
= m_info_hash
[hashid
]; mi
; mi
= mi
->m_next
) {
2964 if (mi
->m_blkno
== blockno
)
2972 meta_delete_all(void)
2974 meta_info_t mi
, next
;
2977 for (i
= 0; i
< HASH_MASK
; i
++) {
2978 for (mi
= m_info_hash
[i
]; mi
; mi
= next
) {
2984 m_info_hash
[i
] = NULL
;
2988 #pragma mark event ("thread info") routines
2990 th_info_t th_info_hash
[HASH_SIZE
];
2991 th_info_t th_info_freelist
;
2994 add_event(ktrace_event_t event
, int type
)
3000 if ((ti
= th_info_freelist
))
3001 th_info_freelist
= ti
->next
;
3003 ti
= malloc(sizeof (struct th_info
));
3005 bzero(ti
, sizeof (struct th_info
));
3007 hashid
= event
->threadid
& HASH_MASK
;
3009 ti
->next
= th_info_hash
[hashid
];
3010 th_info_hash
[hashid
] = ti
;
3012 eventid
= event
->debugid
& KDBG_EVENTID_MASK
;
3014 if (eventid
== BSC_execve
|| eventid
== BSC_posix_spawn
) {
3015 const char *command
;
3017 command
= ktrace_get_execname_for_thread(s
, event
->threadid
);
3022 strncpy(ti
->command
, command
, sizeof (ti
->command
));
3023 ti
->command
[MAXCOMLEN
] = '\0';
3026 ti
->thread
= event
->threadid
;
3033 event_find(uint64_t thread
, int type
)
3038 hashid
= thread
& HASH_MASK
;
3040 for (ti
= th_info_hash
[hashid
]; ti
; ti
= ti
->next
) {
3041 if (ti
->thread
== thread
) {
3042 if (type
== ti
->type
)
3054 event_delete(th_info_t ti_to_delete
)
3060 hashid
= ti_to_delete
->thread
& HASH_MASK
;
3062 if ((ti
= th_info_hash
[hashid
])) {
3063 if (ti
== ti_to_delete
)
3064 th_info_hash
[hashid
] = ti
->next
;
3068 for (ti
= ti
->next
; ti
; ti
= ti
->next
) {
3069 if (ti
== ti_to_delete
) {
3070 ti_prev
->next
= ti
->next
;
3077 ti
->next
= th_info_freelist
;
3078 th_info_freelist
= ti
;
3084 event_delete_all(void)
3087 th_info_t ti_next
= 0;
3090 for (i
= 0; i
< HASH_SIZE
; i
++) {
3092 for (ti
= th_info_hash
[i
]; ti
; ti
= ti_next
) {
3094 ti
->next
= th_info_freelist
;
3095 th_info_freelist
= ti
;
3097 th_info_hash
[i
] = 0;
3102 event_enter(int type
, ktrace_event_t event
)
3113 case P_CS_SYNC_DISK
:
3123 if ((type
& CSC_MASK
) == BSC_BASE
) {
3124 if ((index
= BSC_INDEX(type
)) < MAX_BSD_SYSCALL
&& bsd_syscalls
[index
].sc_name
)
3131 if ((ti
= add_event(event
, type
)) == NULL
)
3134 ti
->stime
= event
->timestamp
;
3135 ti
->arg1
= event
->arg1
;
3136 ti
->arg2
= event
->arg2
;
3137 ti
->arg3
= event
->arg3
;
3138 ti
->arg4
= event
->arg4
;
3142 event_exit(char *sc_name
, int type
, ktrace_event_t event
, int format
)
3147 if ((ti
= event_find(event
->threadid
, type
)) == NULL
)
3150 pid
= ktrace_get_pid_for_thread(s
, event
->threadid
);
3152 if (check_filter_mode(pid
, ti
, type
, (int)event
->arg1
, (int)event
->arg2
, sc_name
)) {
3153 const char *pathname
;
3157 /* most things are just interested in the first lookup */
3158 if (ti
->pathname
[0] != '\0')
3159 pathname
= ti
->pathname
;
3164 format_print(ti
, sc_name
, event
, type
, format
, event
->timestamp
, ti
->stime
, ti
->waited
, pathname
, NULL
);
3171 event_mark_thread_waited(uint64_t thread
)
3176 hashid
= thread
& HASH_MASK
;
3178 for (ti
= th_info_hash
[hashid
]; ti
; ti
= ti
->next
) {
3179 if (ti
->thread
== thread
)
3184 #pragma mark network fd set routines
3187 struct pid_fd_set
*next
;
3190 size_t setsize
; /* number of *bytes*, not bits */
3193 struct pid_fd_set
*pfs_hash
[HASH_SIZE
];
3195 static struct pid_fd_set
*
3198 struct pid_fd_set
*pfs
;
3201 os_assert(pid
>= 0);
3203 hashid
= pid
& HASH_MASK
;
3205 for (pfs
= pfs_hash
[hashid
]; pfs
; pfs
= pfs
->next
) {
3206 if (pfs
->pid
== pid
) {
3211 pfs
= calloc(1, sizeof (struct pid_fd_set
));
3216 pfs
->next
= pfs_hash
[hashid
];
3217 pfs_hash
[hashid
] = pfs
;
3223 fd_clear_pid(pid_t pid
)
3225 struct pid_fd_set
*pfs
, *prev
;
3231 hashid
= pid
& HASH_MASK
;
3233 pfs
= pfs_hash
[hashid
];
3237 if (pfs
->pid
== pid
) {
3239 prev
->next
= pfs
->next
;
3241 pfs_hash
[hashid
] = pfs
->next
;
3258 struct pid_fd_set
*pfs
, *next
;
3261 for (i
= 0; i
< HASH_SIZE
; i
++) {
3262 for (pfs
= pfs_hash
[i
]; pfs
; pfs
= next
) {
3274 fd_set_is_network(pid_t pid
, uint64_t fd
, bool set
)
3276 struct pid_fd_set
*pfs
;
3285 if (fd
>= pfs
->setsize
* CHAR_BIT
) {
3290 newsize
= MAX(((size_t)fd
+ CHAR_BIT
) / CHAR_BIT
, 2 * pfs
->setsize
);
3291 pfs
->set
= reallocf(pfs
->set
, newsize
);
3292 os_assert(pfs
->set
!= NULL
);
3294 bzero(pfs
->set
+ pfs
->setsize
, newsize
- pfs
->setsize
);
3295 pfs
->setsize
= newsize
;
3299 setbit(pfs
->set
, fd
);
3301 clrbit(pfs
->set
, fd
);
3305 fd_is_network(pid_t pid
, uint64_t fd
)
3307 struct pid_fd_set
*pfs
;
3314 if (fd
>= pfs
->setsize
* CHAR_BIT
) {
3318 return isset(pfs
->set
, fd
);
3321 #pragma mark shared region address lookup routines
3323 #define MAXINDEX 2048
3325 struct library_range
{
3330 struct library_info
{
3337 struct library_range frameworkArm64e
= {0, 0};
3338 struct library_range framework64
= {0, 0};
3339 struct library_range framework64h
= {0, 0};
3341 struct library_info library_infos
[MAXINDEX
];
3342 int num_libraries
= 0;
3350 #define LINKEDIT_R 6
3353 sort_library_addresses(void)
3355 library_infos
[num_libraries
].b_address
= library_infos
[num_libraries
- 1].b_address
+ 0x800000;
3356 library_infos
[num_libraries
].e_address
= library_infos
[num_libraries
].b_address
;
3357 library_infos
[num_libraries
].name
= NULL
;
3359 qsort_b(library_infos
, num_libraries
, sizeof (struct library_info
), ^int(const void *aa
, const void *bb
) {
3360 struct library_info
*a
= (struct library_info
*)aa
;
3361 struct library_info
*b
= (struct library_info
*)bb
;
3363 if (a
->b_address
< b
->b_address
) return -1;
3364 if (a
->b_address
== b
->b_address
) return 0;
3370 scanline(char *inputstring
, char **argv
, int maxtokens
)
3373 char **ap
= argv
, *p
, *val
;
3375 for (p
= inputstring
; n
< maxtokens
&& p
!= NULL
; ) {
3376 while ((val
= strsep(&p
, " \t")) != NULL
&& *val
== '\0') ;
3388 read_shared_cache_map(const char *path
, struct library_range
*lr
, char *linkedit_name
)
3390 uint64_t b_address
, e_address
;
3392 char *fnp
, *fn_tofree
;
3394 char frameworkName
[256];
3398 int linkedit_found
= 0;
3399 char *substring
, *ptr
;
3401 bzero(buf
, sizeof(buf
));
3402 bzero(tokens
, sizeof(tokens
));
3407 if ((fd
= fopen(path
, "r")) == 0)
3410 while (fgets(buf
, 1023, fd
)) {
3411 if (strncmp(buf
, "mapping", 7))
3415 buf
[strlen(buf
)-1] = 0;
3417 frameworkName
[0] = 0;
3421 * Extract lib name from path name
3423 if ((substring
= strrchr(buf
, '.'))) {
3425 * There is a ".": name is whatever is between the "/" around the "."
3427 while ( *substring
!= '/') /* find "/" before "." */
3432 strncpy(frameworkName
, substring
, 256); /* copy path from "/" */
3433 frameworkName
[255] = 0;
3434 substring
= frameworkName
;
3436 while ( *substring
!= '/' && *substring
) /* find "/" after "." and stop string there */
3442 * No ".": take segment after last "/"
3449 substring
= ptr
+ 1;
3453 strncpy(frameworkName
, substring
, 256);
3454 frameworkName
[255] = 0;
3457 fnp
= malloc(strlen(frameworkName
) + 1);
3459 strcpy(fnp
, frameworkName
);
3461 while (fgets(buf
, 1023, fd
) && num_libraries
< (MAXINDEX
- 2)) {
3465 buf
[strlen(buf
)-1] = 0;
3467 ntokens
= scanline(buf
, tokens
, 64);
3472 if (strncmp(tokens
[0], "__TEXT", 6) == 0)
3474 else if (strncmp(tokens
[0], "__DATA", 6) == 0)
3476 else if (strncmp(tokens
[0], "__OBJC", 6) == 0)
3478 else if (strncmp(tokens
[0], "__IMPORT", 8) == 0)
3480 else if (strncmp(tokens
[0], "__UNICODE", 9) == 0)
3482 else if (strncmp(tokens
[0], "__IMAGE", 7) == 0)
3484 else if (strncmp(tokens
[0], "__LINKEDIT", 10) == 0)
3489 if (type
== LINKEDIT_R
&& linkedit_found
)
3493 b_address
= strtoull(tokens
[1], 0, 16);
3494 e_address
= strtoull(tokens
[3], 0, 16);
3496 library_infos
[num_libraries
].b_address
= b_address
;
3497 library_infos
[num_libraries
].e_address
= e_address
;
3498 library_infos
[num_libraries
].r_type
= type
;
3500 if (type
== LINKEDIT_R
) {
3501 library_infos
[num_libraries
].name
= linkedit_name
;
3504 library_infos
[num_libraries
].name
= fnp
;
3508 printf("%s(%d): %qx-%qx\n", frameworkInfo
[numFrameworks
].name
, type
, b_address
, e_address
);
3510 if (lr
->b_address
== 0 || b_address
< lr
->b_address
)
3511 lr
->b_address
= b_address
;
3513 if (lr
->e_address
== 0 || e_address
> lr
->e_address
)
3514 lr
->e_address
= e_address
;
3519 if (type
== LINKEDIT_R
)
3525 if (fgets(buf
, 1023, fd
) == 0)
3528 buf
[strlen(buf
)-1] = 0;
3534 printf("%s range, %qx-%qx\n", path
, lr
->b_address
, lr
->e_address
);
3539 #define DYLD_SHARED_CACHE_LOCATION "/System/Library/dyld/"
3542 init_shared_cache_mapping(void)
3545 #if TARGET_CPU_ARM64
3546 read_shared_cache_map(DYLD_SHARED_CACHE_LOCATION
"dyld_shared_cache_arm64e.map", &frameworkArm64e
, DYLD_SHARED_CACHE_LOCATION
"dyld_shared_cache_arm64e");
3547 #else //!TARGET_CPU_ARM64
3548 if (0 == read_shared_cache_map(DYLD_SHARED_CACHE_LOCATION
"dyld_shared_cache_x86_64h.map", &framework64h
, DYLD_SHARED_CACHE_LOCATION
"dyld_shared_cache_x86_64h")) {
3549 read_shared_cache_map(DYLD_SHARED_CACHE_LOCATION
"dyld_shared_cache_x86_64.map", &framework64
, DYLD_SHARED_CACHE_LOCATION
"dyld_shared_cache_x86_64");
3551 #endif //TARGET_CPU_ARM64
3552 sort_library_addresses();
3553 #endif //TARGET_OS_OSX
3557 lookup_name(uint64_t user_addr
, char **type
, char **name
)
3562 static char *frameworkType
[] = {
3575 if (num_libraries
) {
3576 if ((user_addr
>= frameworkArm64e
.b_address
&& user_addr
< frameworkArm64e
.e_address
) ||
3577 (user_addr
>= framework64
.b_address
&& user_addr
< framework64
.e_address
) ||
3578 (user_addr
>= framework64h
.b_address
&& user_addr
< framework64h
.e_address
)) {
3581 last
= num_libraries
;
3583 for (i
= num_libraries
/ 2; start
< last
; i
= start
+ ((last
- start
) / 2)) {
3584 if (user_addr
> library_infos
[i
].e_address
)
3590 if (start
< num_libraries
&&
3591 user_addr
>= library_infos
[start
].b_address
&& user_addr
< library_infos
[start
].e_address
) {
3592 *type
= frameworkType
[library_infos
[start
].r_type
];
3593 *name
= library_infos
[start
].name
;
3599 #pragma mark disk I/O tracking routines
3601 struct diskio
*free_diskios
= NULL
;
3602 struct diskio
*busy_diskios
= NULL
;
3605 diskio_start(uint64_t type
, uint64_t bp
, uint64_t dev
,
3606 uint64_t blkno
, uint64_t iosize
, ktrace_event_t event
)
3608 const char *command
;
3611 if ((dio
= free_diskios
)) {
3612 free_diskios
= dio
->next
;
3614 dio
= malloc(sizeof (struct diskio
));
3623 dio
->iosize
= iosize
;
3624 dio
->issued_time
= event
->timestamp
;
3625 dio
->issuing_thread
= event
->threadid
;
3626 dio
->issuing_pid
= ktrace_get_pid_for_thread(s
, event
->threadid
);
3630 command
= ktrace_get_execname_for_thread(s
, event
->threadid
);
3635 strncpy(dio
->issuing_command
, command
, MAXCOMLEN
);
3636 dio
->issuing_command
[MAXCOMLEN
] = '\0';
3638 dio
->next
= busy_diskios
;
3641 dio
->next
->prev
= dio
;
3649 diskio_find(uint64_t bp
)
3653 for (dio
= busy_diskios
; dio
; dio
= dio
->next
) {
3662 diskio_complete(uint64_t bp
, uint64_t io_errno
, uint64_t resid
,
3663 uint64_t thread
, uint64_t curtime
, struct timeval curtime_wall
)
3667 if ((dio
= diskio_find(bp
)) == NULL
) return NULL
;
3669 if (dio
== busy_diskios
) {
3670 if ((busy_diskios
= dio
->next
))
3671 dio
->next
->prev
= NULL
;
3674 dio
->next
->prev
= dio
->prev
;
3675 dio
->prev
->next
= dio
->next
;
3678 dio
->iosize
-= resid
;
3679 dio
->io_errno
= io_errno
;
3680 dio
->completed_time
= curtime
;
3681 dio
->completed_walltime
= curtime_wall
;
3682 dio
->completion_thread
= thread
;
3688 diskio_free(struct diskio
*dio
)
3690 dio
->next
= free_diskios
;
3695 diskio_print(struct diskio
*dio
)
3700 int format
= FMT_DISKIO
;
3706 if ((type
& P_CS_Class
) == P_CS_Class
) {
3708 case P_CS_ReadChunk
:
3711 format
= FMT_DISKIO_CS
;
3713 case P_CS_WriteChunk
:
3716 format
= FMT_DISKIO_CS
;
3721 format
= FMT_DISKIO_CS
;
3723 case P_CS_MetaWrite
:
3726 format
= FMT_DISKIO_CS
;
3728 case P_CS_TransformRead
:
3732 case P_CS_TransformWrite
:
3736 case P_CS_MigrationRead
:
3740 case P_CS_MigrationWrite
:
3750 strncpy(buf
, p
, len
);
3752 switch (type
& P_DISKIO_TYPE
) {
3785 strncpy(buf
, p
, len
);
3789 if (type
& P_DISKIO_ASYNC
)
3794 if (type
& P_DISKIO_NOCACHE
)
3797 int tier
= (type
& P_DISKIO_TIER_MASK
) >> P_DISKIO_TIER_SHIFT
;
3801 if (tier
> 0 && tier
< 10)
3802 buf
[len
++] = '0' + tier
;
3804 if (type
& P_DISKIO_TIER_UPGRADE
) {
3809 if (type
& P_DISKIO_PASSIVE
)
3817 if (check_filter_mode(-1, NULL
, type
, 0, 0, buf
)) {
3818 const char *pathname
= ktrace_get_path_for_vp(s
, dio
->vnodeid
);
3819 format_print(NULL
, buf
, NULL
, type
, format
, dio
->completed_time
,
3820 dio
->issued_time
, 1, pathname
? pathname
: "", dio
);
3824 #pragma mark disk name routines
3827 struct diskrec
*next
;
3832 struct diskrec
*disk_list
= NULL
;
3835 cache_disk_names(void)
3840 struct diskrec
*dnp
;
3842 if ((dirp
= opendir("/dev")) == NULL
)
3845 while ((dir
= readdir(dirp
)) != NULL
) {
3846 char nbuf
[MAXPATHLEN
];
3848 if (dir
->d_namlen
< 5 || strncmp("disk", dir
->d_name
, 4))
3851 snprintf(nbuf
, MAXPATHLEN
, "%s/%s", "/dev", dir
->d_name
);
3853 if (stat(nbuf
, &st
) < 0)
3856 if ((dnp
= malloc(sizeof(struct diskrec
))) == NULL
)
3859 if ((dnp
->diskname
= malloc(dir
->d_namlen
+ 1)) == NULL
) {
3863 strncpy(dnp
->diskname
, dir
->d_name
, dir
->d_namlen
);
3864 dnp
->diskname
[dir
->d_namlen
] = 0;
3865 dnp
->dev
= st
.st_rdev
;
3867 dnp
->next
= disk_list
;
3875 recache_disk_names(void)
3877 struct diskrec
*dnp
, *next_dnp
;
3879 for (dnp
= disk_list
; dnp
; dnp
= next_dnp
) {
3880 next_dnp
= dnp
->next
;
3882 free(dnp
->diskname
);
3891 find_disk_name(uint64_t dev
)
3893 struct diskrec
*dnp
;
3902 for (i
= 0; i
< 2; i
++) {
3903 for (dnp
= disk_list
; dnp
; dnp
= dnp
->next
) {
3904 if (dnp
->dev
== dev
)
3905 return (dnp
->diskname
);
3907 recache_disk_names();
3914 generate_cs_disk_name(uint64_t dev
, char *s
)
3919 sprintf(s
, "disk%" PRIu64
"s%" PRIu64
, (dev
>> 16) & 0xffff, dev
& 0xffff);