/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2019 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
/*
-cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -DPRIVATE -D__APPLE_PRIVATE -arch x86_64 -arch i386 -O -lutil -o fs_usage fs_usage.c
-*/
+ * 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
+ */
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <strings.h>
-#include <nlist.h>
#include <fcntl.h>
#include <aio.h>
#include <string.h>
#include <err.h>
#include <libutil.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/time.h>
+#include <ktrace/session.h>
+#include <System/sys/kdebug.h>
+#include <os/assumes.h>
+
+#include <sys/disk.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
#include <sys/ioctl.h>
-#include <sys/socket.h>
#include <sys/mman.h>
-#include <sys/sysctl.h>
-#include <sys/disk.h>
-
-#ifndef KERNEL_PRIVATE
-#define KERNEL_PRIVATE
-#include <sys/kdebug.h>
-#undef KERNEL_PRIVATE
-#else
-#include <sys/kdebug.h>
-#endif /*KERNEL_PRIVATE*/
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/syslimits.h>
+#include <sys/time.h>
+#include <sys/types.h>
#import <mach/clock_types.h>
#import <mach/mach_time.h>
-
-
-#define F_OPENFROM 56 /* SPI: open a file relative to fd (must be a dir) */
-#define F_UNLINKFROM 57 /* SPI: open a file relative to fd (must be a dir) */
-#define F_CHECK_OPENEVT 58 /* SPI: if a process is marked OPENEVT, or in O_EVTONLY on opens of this vnode */
-
-
-#ifndef RAW_VERSION1
-typedef struct {
- int version_no;
- int thread_count;
- uint64_t TOD_secs;
- uint32_t TOD_usecs;
-} RAW_header;
-
-#define RAW_VERSION0 0x55aa0000
-#define RAW_VERSION1 0x55aa0101
-#endif
-
-
-#define MAXINDEX 2048
-
-typedef struct LibraryRange {
- uint64_t b_address;
- uint64_t e_address;
-} LibraryRange;
-
-LibraryRange framework32;
-LibraryRange framework64;
-
-
-#define TEXT_R 0
-#define DATA_R 1
-#define OBJC_R 2
-#define IMPORT_R 3
-#define UNICODE_R 4
-#define IMAGE_R 5
-#define LINKEDIT_R 6
-
-
-char *frameworkType[] = {
- "<TEXT> ",
- "<DATA> ",
- "<OBJC> ",
- "<IMPORT> ",
- "<UNICODE> ",
- "<IMAGE> ",
- "<LINKEDIT>",
-};
-
-
-typedef struct LibraryInfo {
- uint64_t b_address;
- uint64_t e_address;
- int r_type;
- char *name;
-} LibraryInfo;
-
-LibraryInfo frameworkInfo[MAXINDEX];
-int numFrameworks = 0;
-
-
-/*
+/*
* MAXCOLS controls when extra data kicks in.
* MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
- * If NUMPARMS changes to match the kernel, it will automatically
- * get reflected in the -w mode output.
*/
-#define NUMPARMS 23
-#define PATHLENGTH (NUMPARMS*sizeof(uintptr_t))
-
#define MAXCOLS 132
-#define MAX_WIDE_MODE_COLS (PATHLENGTH + 80)
+#define MAX_WIDE_MODE_COLS 264
#define MAXWIDTH MAX_WIDE_MODE_COLS + 64
+typedef struct th_info {
+ struct th_info *next;
+ uint64_t thread;
-typedef struct th_info *th_info_t;
-
-struct th_info {
- th_info_t next;
- uintptr_t thread;
- uintptr_t child_thread;
-
- int in_filemgr;
- int pid;
- int type;
- int arg1;
- int arg2;
- int arg3;
- int arg4;
- int arg5;
- int arg6;
- int arg7;
- int arg8;
- int waited;
- double stime;
- uintptr_t *pathptr;
- uintptr_t pathname[NUMPARMS + 1]; /* add room for null terminator */
- uintptr_t pathname2[NUMPARMS + 1]; /* add room for null terminator */
-};
-
-
-typedef struct threadmap * threadmap_t;
+ /* this is needed for execve()/posix_spawn(), because the command name at the end probe is the new name, which we don't want */
+ char command[MAXCOMLEN + 1];
-struct threadmap {
- threadmap_t tm_next;
+ /*
+ * sometimes a syscall can cause multiple VFS_LOOKUPs of the same vnode with multiple paths
+ * (e.g., one absolute, one relative). traditional fs_usage behavior was to display the
+ * *first* lookup, so we need to save it off once we see it.
+ */
+ uint64_t vnodeid; /* the vp of the VFS_LOOKUP we're currently in, 0 if we are not in one */
+ char pathname[MAXPATHLEN];
+ char pathname2[MAXPATHLEN];
+ char *newest_pathname; /* points to pathname2 if it's filled, otherwise pathname if it's filled, otherwise NULL */
+
+ int pid;
+ int type;
+ uint64_t arg1;
+ uint64_t arg2;
+ uint64_t arg3;
+ uint64_t arg4;
+ uint64_t arg5;
+ uint64_t arg6;
+ uint64_t arg7;
+ uint64_t arg8;
+ int waited;
+ uint64_t stime;
+} *th_info_t;
- uintptr_t tm_thread;
- unsigned int tm_setsize; /* this is a bit count */
- unsigned long *tm_setptr; /* file descripter bitmap */
- char tm_command[MAXCOMLEN + 1];
+struct diskio {
+ struct diskio *next;
+ struct diskio *prev;
+ uint64_t type;
+ uint64_t bp;
+ uint64_t dev;
+ uint64_t blkno;
+ uint64_t iosize;
+ uint64_t io_errno;
+ uint64_t is_meta;
+ uint64_t vnodeid;
+ uint64_t issuing_thread;
+ pid_t issuing_pid;
+ uint64_t completion_thread;
+ char issuing_command[MAXCOMLEN + 1];
+ uint64_t issued_time;
+ uint64_t completed_time;
+ struct timeval completed_walltime;
+ uint32_t bc_info;
};
-
#define HASH_SIZE 1024
-#define HASH_MASK 1023
-
-th_info_t th_info_hash[HASH_SIZE];
-th_info_t th_info_freelist;
-
-threadmap_t threadmap_hash[HASH_SIZE];
-threadmap_t threadmap_freelist;
-
-
-int filemgr_in_progress = 0;
-int need_new_map = 1;
-int bias_secs = 0;
-long last_time;
-int wideflag = 0;
-int columns = 0;
-
-int one_good_pid = 0; /* Used to fail gracefully when bad pids given */
-int select_pid_mode = 0; /* Flag set indicates that output is restricted
- to selected pids or commands */
-
-char *arguments = 0;
-int argmax = 0;
-
-
-#define USLEEP_MIN 1
-#define USLEEP_BEHIND 2
-#define USLEEP_MAX 32
-int usleep_ms = USLEEP_MIN;
-
-/*
- * Network only or filesystem only output filter
- * Default of zero means report all activity - no filtering
- */
-#define FILESYS_FILTER 0x01
-#define NETWORK_FILTER 0x02
-#define CACHEHIT_FILTER 0x04
-#define EXEC_FILTER 0x08
-#define PATHNAME_FILTER 0x10
-#define DEFAULT_DO_NOT_FILTER 0x00
-
-int filter_mode = CACHEHIT_FILTER;
-
+#define HASH_MASK (HASH_SIZE - 1)
+
+void setup_ktrace_callbacks(void);
+void extend_syscall(uint64_t thread, int type, ktrace_event_t event);
+
+/* printing routines */
+bool check_filter_mode(pid_t pid, th_info_t ti, uint64_t type, int error, int retval, char *sc_name);
+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);
+int print_open(ktrace_event_t event, uint64_t flags);
+
+/* metadata info hash routines */
+void meta_add_name(uint64_t blockno, const char *pathname);
+const char *meta_find_name(uint64_t blockno);
+void meta_delete_all(void);
+
+/* event ("thread info") routines */
+void event_enter(int type, ktrace_event_t event);
+void event_exit(char *sc_name, int type, ktrace_event_t event, int format);
+th_info_t event_find(uint64_t thread, int type);
+void event_delete(th_info_t ti_to_delete);
+void event_delete_all(void);
+void event_mark_thread_waited(uint64_t);
+
+/* network fd set routines */
+void fd_set_is_network(pid_t pid, uint64_t fd, bool set);
+bool fd_is_network(pid_t pid, uint64_t fd);
+void fd_clear_pid(pid_t pid);
+void fd_clear_all(void);
+
+/* shared region address lookup routines */
+void init_shared_cache_mapping(void);
+void lookup_name(uint64_t user_addr, char **type, char **name);
+
+/* disk I/O tracking routines */
+struct diskio *diskio_start(uint64_t type, uint64_t bp, uint64_t dev, uint64_t blkno, uint64_t iosize, ktrace_event_t event);
+struct diskio *diskio_find(uint64_t bp);
+struct diskio *diskio_complete(uint64_t bp, uint64_t io_errno, uint64_t resid, uint64_t thread, uint64_t curtime, struct timeval curtime_wall);
+void diskio_print(struct diskio *dio);
+void diskio_free(struct diskio *dio);
+
+/* disk name routines */
#define NFS_DEV -1
#define CS_DEV -2
-
-struct diskrec {
- struct diskrec *next;
- char *diskname;
- int dev;
-};
-
-struct diskio {
- struct diskio *next;
- struct diskio *prev;
- int type;
- int bp;
- int dev;
- int blkno;
- int iosize;
- int io_errno;
- uintptr_t issuing_thread;
- uintptr_t completion_thread;
- char issuing_command[MAXCOMLEN];
- double issued_time;
- double completed_time;
-};
-
-struct diskrec *disk_list = NULL;
-struct diskio *free_diskios = NULL;
-struct diskio *busy_diskios = NULL;
-
-
-struct diskio *insert_diskio();
-struct diskio *complete_diskio();
-void free_diskio();
-void print_diskio();
-
-int check_filter_mode(struct th_info *, int, int, int, char *);
-void format_print(struct th_info *, char *, uintptr_t, int, int, int, int, int, int, double, double, int, char *, struct diskio *);
-void enter_event_now(uintptr_t, int, kd_buf *, char *, double);
-void enter_event(uintptr_t, int, kd_buf *, char *, double);
-void exit_event(char *, uintptr_t, int, int, int, int, int, int, double);
-void extend_syscall(uintptr_t, int, kd_buf *);
-
-char *generate_cs_disk_name(int, char *s);
-char *find_disk_name(int);
-void cache_disk_names();
-void recache_disk_names();
-
-void lookup_name(uint64_t user_addr, char **type, char **name);
-int ReadSharedCacheMap(const char *, LibraryRange *, char *);
-void SortFrameworkAddresses();
-
-void fs_usage_fd_set(uintptr_t, unsigned int);
-int fs_usage_fd_isset(uintptr_t, unsigned int);
-void fs_usage_fd_clear(uintptr_t, unsigned int);
-
-void init_arguments_buffer();
-int get_real_command_name(int, char *, int);
-
-void delete_all_events();
-void delete_event(th_info_t);
-th_info_t add_event(uintptr_t, int);
-th_info_t find_event(uintptr_t, int);
-void mark_thread_waited(uintptr_t);
-
-void read_command_map();
-void delete_all_map_entries();
-void create_map_entry(uintptr_t, int, char *);
-void delete_map_entry(uintptr_t);
-threadmap_t find_map_entry(uintptr_t);
-
-void getdivisor();
-void argtopid();
-void set_remove();
-void set_pidcheck();
-void set_pidexclude();
-int quit();
-
+char *generate_cs_disk_name(uint64_t dev, char *s);
+char *find_disk_name(uint64_t dev);
+void cache_disk_names(void);
#define CLASS_MASK 0xff000000
#define CSC_MASK 0xffff0000
#define BSC_INDEX(type) ((type >> 2) & 0x3fff)
-
-#define TRACE_DATA_NEWTHREAD 0x07000004
-#define TRACE_DATA_EXEC 0x07000008
-#define TRACE_STRING_NEWTHREAD 0x07010004
-#define TRACE_STRING_EXEC 0x07010008
-
#define MACH_vmfault 0x01300008
#define MACH_pageout 0x01300004
#define MACH_sched 0x01400000
#define MACH_stkhandoff 0x01400008
#define MACH_idle 0x01400024
-#define VFS_LOOKUP 0x03010090
#define BSC_thread_terminate 0x040c05a4
+#define HFS_update 0x3018000
+#define HFS_modify_block_end 0x3018004
+
#define Throttled 0x3010184
#define SPEC_ioctl 0x3060000
#define SPEC_unmap_info 0x3060004
#define proc_exit 0x4010004
-#ifndef DKIO_NOCACHE
-#define DKIO_NOCACHE 0x80
-#endif
+#define BC_IO_HIT 0x03070010
+#define BC_IO_HIT_STALLED 0x03070020
+#define BC_IO_MISS 0x03070040
+#define BC_IO_MISS_CUT_THROUGH 0x03070080
+#define BC_PLAYBACK_IO 0x03070100
+#define BC_STR(s) ( \
+ (s == BC_IO_HIT) ? "HIT" : \
+ (s == BC_IO_HIT_STALLED) ? "STALL" : \
+ (s == BC_IO_MISS) ? "MISS" : \
+ (s == BC_IO_MISS_CUT_THROUGH) ? "CUT" : \
+ (s == BC_PLAYBACK_IO) ? "PLBK" : \
+ (s == 0x0) ? "NONE" : "UNKN" )
#define P_DISKIO_READ (DKIO_READ << 2)
#define P_DISKIO_ASYNC (DKIO_ASYNC << 2)
#define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
#define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
#define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
+#define P_DISKIO_TIER_MASK (DKIO_TIER_MASK << 2)
+#define P_DISKIO_TIER_SHIFT (DKIO_TIER_SHIFT + 2)
+#define P_DISKIO_TIER_UPGRADE (DKIO_TIER_UPGRADE << 2)
#define P_DISKIO (FSDBG_CODE(DBG_DKRW, 0))
#define P_DISKIO_DONE (P_DISKIO | (DKIO_DONE << 2))
#define MSC_map_fd 0x010c00ac
#define BSC_BASE 0x040C0000
-#define MSC_BASE 0x010C0000
// Network related codes
#define BSC_recvmsg 0x040C006C
#define BSC_listen 0x040C01A8
#define BSC_sendto 0x040C0214
#define BSC_socketpair 0x040C021C
+#define BSC_recvmsg_nocancel 0x040c0644
+#define BSC_sendmsg_nocancel 0x040c0648
+#define BSC_recvfrom_nocancel 0x040c064c
+#define BSC_accept_nocancel 0x040c0650
+#define BSC_connect_nocancel 0x040c0664
+#define BSC_sendto_nocancel 0x040c0674
#define BSC_exit 0x040C0004
#define BSC_read 0x040C000C
#define BSC_dup 0x040C00A4
#define BSC_ioctl 0x040C00D8
#define BSC_revoke 0x040C00E0
-#define BSC_symlink 0x040C00E4
+#define BSC_symlink 0x040C00E4
#define BSC_readlink 0x040C00E8
#define BSC_execve 0x040C00EC
#define BSC_umask 0x040C00F0
#define BSC_msync 0x040C0104
#define BSC_dup2 0x040C0168
#define BSC_fcntl 0x040C0170
-#define BSC_fsync 0x040C017C
-#define BSC_readv 0x040C01E0
-#define BSC_writev 0x040C01E4
-#define BSC_fchown 0x040C01EC
-#define BSC_fchmod 0x040C01F0
+#define BSC_fsync 0x040C017C
+#define BSC_readv 0x040C01E0
+#define BSC_writev 0x040C01E4
+#define BSC_fchown 0x040C01EC
+#define BSC_fchmod 0x040C01F0
#define BSC_rename 0x040C0200
-#define BSC_mkfifo 0x040c0210
-#define BSC_mkdir 0x040C0220
+#define BSC_flock 0x040C020C
+#define BSC_mkfifo 0x040C0210
+#define BSC_mkdir 0x040C0220
#define BSC_rmdir 0x040C0224
#define BSC_utimes 0x040C0228
#define BSC_futimes 0x040C022C
#define BSC_pread 0x040C0264
#define BSC_pwrite 0x040C0268
-#define BSC_statfs 0x040C0274
+#define BSC_statfs 0x040C0274
#define BSC_fstatfs 0x040C0278
#define BSC_unmount 0x040C027C
#define BSC_mount 0x040C029C
-#define BSC_stat 0x040C02F0
-#define BSC_fstat 0x040C02F4
-#define BSC_lstat 0x040C02F8
-#define BSC_pathconf 0x040C02FC
+#define BSC_fdatasync 0x040C02EC
+#define BSC_stat 0x040C02F0
+#define BSC_fstat 0x040C02F4
+#define BSC_lstat 0x040C02F8
+#define BSC_pathconf 0x040C02FC
#define BSC_fpathconf 0x040C0300
#define BSC_getdirentries 0x040C0310
#define BSC_mmap 0x040c0314
#define BSC_lseek 0x040c031c
#define BSC_truncate 0x040C0320
-#define BSC_ftruncate 0x040C0324
+#define BSC_ftruncate 0x040C0324
#define BSC_undelete 0x040C0334
-#define BSC_statv 0x040C0364
-#define BSC_lstatv 0x040C0368
-#define BSC_fstatv 0x040C036C
-#define BSC_mkcomplex 0x040C0360
-#define BSC_getattrlist 0x040C0370
-#define BSC_setattrlist 0x040C0374
-#define BSC_getdirentriesattr 0x040C0378
-#define BSC_exchangedata 0x040C037C
-#define BSC_checkuseraccess 0x040C0380
-#define BSC_searchfs 0x040C0384
-#define BSC_delete 0x040C0388
-#define BSC_copyfile 0x040C038C
+#define BSC_open_dprotected_np 0x040C0360
+#define BSC_getattrlist 0x040C0370
+#define BSC_setattrlist 0x040C0374
+#define BSC_getdirentriesattr 0x040C0378
+#define BSC_exchangedata 0x040C037C
+#define BSC_checkuseraccess 0x040C0380
+#define BSC_searchfs 0x040C0384
+#define BSC_delete 0x040C0388
+#define BSC_copyfile 0x040C038C
+#define BSC_fgetattrlist 0x040C0390
+#define BSC_fsetattrlist 0x040C0394
#define BSC_getxattr 0x040C03A8
#define BSC_fgetxattr 0x040C03AC
#define BSC_setxattr 0x040C03B0
#define BSC_fremovexattr 0x040C03BC
#define BSC_listxattr 0x040C03C0
#define BSC_flistxattr 0x040C03C4
-#define BSC_fsctl 0x040C03C8
-#define BSC_posix_spawn 0x040C03D0
+#define BSC_fsctl 0x040C03C8
+#define BSC_posix_spawn 0x040C03D0
+#define BSC_ffsctl 0x040C03D4
#define BSC_open_extended 0x040C0454
+#define BSC_umask_extended 0x040C0458
#define BSC_stat_extended 0x040C045C
#define BSC_lstat_extended 0x040C0460
#define BSC_fstat_extended 0x040C0464
#define BSC_access_extended 0x040C0470
#define BSC_mkfifo_extended 0x040C048C
#define BSC_mkdir_extended 0x040C0490
-#define BSC_load_shared_file 0x040C04A0
#define BSC_aio_fsync 0x040C04E4
#define BSC_aio_return 0x040C04E8
#define BSC_aio_suspend 0x040C04EC
#define BSC_write_nocancel 0x040c0634
#define BSC_open_nocancel 0x040c0638
#define BSC_close_nocancel 0x040c063c
-#define BSC_recvmsg_nocancel 0x040c0644
-#define BSC_sendmsg_nocancel 0x040c0648
-#define BSC_recvfrom_nocancel 0x040c064c
-#define BSC_accept_nocancel 0x040c0650
#define BSC_msync_nocancel 0x040c0654
#define BSC_fcntl_nocancel 0x040c0658
#define BSC_select_nocancel 0x040c065c
#define BSC_fsync_nocancel 0x040c0660
-#define BSC_connect_nocancel 0x040c0664
#define BSC_readv_nocancel 0x040c066c
#define BSC_writev_nocancel 0x040c0670
-#define BSC_sendto_nocancel 0x040c0674
#define BSC_pread_nocancel 0x040c0678
#define BSC_pwrite_nocancel 0x040c067c
-#define BSC_aio_suspend_nocancel 0x40c0694
+#define BSC_aio_suspend_nocancel 0x40c0694
+#define BSC_guarded_open_np 0x040c06e4
+#define BSC_guarded_open_dprotected_np 0x040c0790
+#define BSC_guarded_close_np 0x040c06e8
+#define BSC_guarded_write_np 0x040c0794
+#define BSC_guarded_pwrite_np 0x040c0798
+#define BSC_guarded_writev_np 0x040c079c
+
+#define BSC_fsgetpath 0x040c06ac
+
+#define BSC_getattrlistbulk 0x040c0734
+
+#define BSC_openat 0x040c073c
+#define BSC_openat_nocancel 0x040c0740
+#define BSC_renameat 0x040c0744
+#define BSC_chmodat 0x040c074c
+#define BSC_chownat 0x040c0750
+#define BSC_fstatat 0x040c0754
+#define BSC_fstatat64 0x040c0758
+#define BSC_linkat 0x040c075c
+#define BSC_unlinkat 0x040c0760
+#define BSC_readlinkat 0x040c0764
+#define BSC_symlinkat 0x040c0768
+#define BSC_mkdirat 0x040c076c
+#define BSC_getattrlistat 0x040c0770
#define BSC_msync_extended 0x040e0104
#define BSC_pread_extended 0x040e0264
#define BSC_pwrite_extended 0x040e0268
+#define BSC_guarded_pwrite_extended 0x040e0798
#define BSC_mmap_extended 0x040e0314
#define BSC_mmap_extended2 0x040f0314
-// Carbon File Manager support
-#define FILEMGR_PBGETCATALOGINFO 0x1e000020
-#define FILEMGR_PBGETCATALOGINFOBULK 0x1e000024
-#define FILEMGR_PBCREATEFILEUNICODE 0x1e000028
-#define FILEMGR_PBCREATEDIRECTORYUNICODE 0x1e00002c
-#define FILEMGR_PBCREATEFORK 0x1e000030
-#define FILEMGR_PBDELETEFORK 0x1e000034
-#define FILEMGR_PBITERATEFORK 0x1e000038
-#define FILEMGR_PBOPENFORK 0x1e00003c
-#define FILEMGR_PBREADFORK 0x1e000040
-#define FILEMGR_PBWRITEFORK 0x1e000044
-#define FILEMGR_PBALLOCATEFORK 0x1e000048
-#define FILEMGR_PBDELETEOBJECT 0x1e00004c
-#define FILEMGR_PBEXCHANGEOBJECT 0x1e000050
-#define FILEMGR_PBGETFORKCBINFO 0x1e000054
-#define FILEMGR_PBGETVOLUMEINFO 0x1e000058
-#define FILEMGR_PBMAKEFSREF 0x1e00005c
-#define FILEMGR_PBMAKEFSREFUNICODE 0x1e000060
-#define FILEMGR_PBMOVEOBJECT 0x1e000064
-#define FILEMGR_PBOPENITERATOR 0x1e000068
-#define FILEMGR_PBRENAMEUNICODE 0x1e00006c
-#define FILEMGR_PBSETCATALOGINFO 0x1e000070
-#define FILEMGR_PBSETVOLUMEINFO 0x1e000074
-#define FILEMGR_FSREFMAKEPATH 0x1e000078
-#define FILEMGR_FSPATHMAKEREF 0x1e00007c
-
-#define FILEMGR_PBGETCATINFO 0x1e010000
-#define FILEMGR_PBGETCATINFOLITE 0x1e010004
-#define FILEMGR_PBHGETFINFO 0x1e010008
-#define FILEMGR_PBXGETVOLINFO 0x1e01000c
-#define FILEMGR_PBHCREATE 0x1e010010
-#define FILEMGR_PBHOPENDF 0x1e010014
-#define FILEMGR_PBHOPENRF 0x1e010018
-#define FILEMGR_PBHGETDIRACCESS 0x1e01001c
-#define FILEMGR_PBHSETDIRACCESS 0x1e010020
-#define FILEMGR_PBHMAPID 0x1e010024
-#define FILEMGR_PBHMAPNAME 0x1e010028
-#define FILEMGR_PBCLOSE 0x1e01002c
-#define FILEMGR_PBFLUSHFILE 0x1e010030
-#define FILEMGR_PBGETEOF 0x1e010034
-#define FILEMGR_PBSETEOF 0x1e010038
-#define FILEMGR_PBGETFPOS 0x1e01003c
-#define FILEMGR_PBREAD 0x1e010040
-#define FILEMGR_PBWRITE 0x1e010044
-#define FILEMGR_PBGETFCBINFO 0x1e010048
-#define FILEMGR_PBSETFINFO 0x1e01004c
-#define FILEMGR_PBALLOCATE 0x1e010050
-#define FILEMGR_PBALLOCCONTIG 0x1e010054
-#define FILEMGR_PBSETFPOS 0x1e010058
-#define FILEMGR_PBSETCATINFO 0x1e01005c
-#define FILEMGR_PBGETVOLPARMS 0x1e010060
-#define FILEMGR_PBSETVINFO 0x1e010064
-#define FILEMGR_PBMAKEFSSPEC 0x1e010068
-#define FILEMGR_PBHGETVINFO 0x1e01006c
-#define FILEMGR_PBCREATEFILEIDREF 0x1e010070
-#define FILEMGR_PBDELETEFILEIDREF 0x1e010074
-#define FILEMGR_PBRESOLVEFILEIDREF 0x1e010078
-#define FILEMGR_PBFLUSHVOL 0x1e01007c
-#define FILEMGR_PBHRENAME 0x1e010080
-#define FILEMGR_PBCATMOVE 0x1e010084
-#define FILEMGR_PBEXCHANGEFILES 0x1e010088
-#define FILEMGR_PBHDELETE 0x1e01008c
-#define FILEMGR_PBDIRCREATE 0x1e010090
-#define FILEMGR_PBCATSEARCH 0x1e010094
-#define FILEMGR_PBHSETFLOCK 0x1e010098
-#define FILEMGR_PBHRSTFLOCK 0x1e01009c
-#define FILEMGR_PBLOCKRANGE 0x1e0100a0
-#define FILEMGR_PBUNLOCKRANGE 0x1e0100a4
-
-
-#define FILEMGR_CLASS 0x1e
-#define FILEMGR_BASE 0x1e000000
-
+#define FMT_NOTHING -1
#define FMT_DEFAULT 0
#define FMT_FD 1
#define FMT_FD_IO 2
#define FMT_SYNC_DISK_CS 38
#define FMT_IOCTL_UNMAP 39
#define FMT_UNMAP_INFO 40
-
-#define MAX_BSD_SYSCALL 512
-
-struct bsd_syscall {
- char *sc_name;
- int sc_format;
-} bsd_syscalls[MAX_BSD_SYSCALL];
-
-
-int bsd_syscall_types[] = {
- BSC_recvmsg,
- BSC_recvmsg_nocancel,
- BSC_sendmsg,
- BSC_sendmsg_nocancel,
- BSC_recvfrom,
- BSC_recvfrom_nocancel,
- BSC_accept,
- BSC_accept_nocancel,
- BSC_select,
- BSC_select_nocancel,
- BSC_socket,
- BSC_connect,
- BSC_connect_nocancel,
- BSC_bind,
- BSC_listen,
- BSC_sendto,
- BSC_sendto_nocancel,
- BSC_socketpair,
- BSC_read,
- BSC_read_nocancel,
- BSC_write,
- BSC_write_nocancel,
- BSC_open,
- BSC_open_nocancel,
- BSC_close,
- BSC_close_nocancel,
- BSC_link,
- BSC_unlink,
- BSC_chdir,
- BSC_fchdir,
- BSC_mknod,
- BSC_chmod,
- BSC_chown,
- BSC_access,
- BSC_chflags,
- BSC_fchflags,
- BSC_sync,
- BSC_dup,
- BSC_revoke,
- BSC_symlink,
- BSC_readlink,
- BSC_exit,
- BSC_execve,
- BSC_posix_spawn,
- BSC_umask,
- BSC_chroot,
- BSC_dup2,
- BSC_fsync,
- BSC_fsync_nocancel,
- BSC_readv,
- BSC_readv_nocancel,
- BSC_writev,
- BSC_writev_nocancel,
- BSC_fchown,
- BSC_fchmod,
- BSC_rename,
- BSC_mkfifo,
- BSC_mkdir,
- BSC_rmdir,
- BSC_utimes,
- BSC_futimes,
- BSC_pread,
- BSC_pread_nocancel,
- BSC_pwrite,
- BSC_pwrite_nocancel,
- BSC_statfs,
- BSC_fstatfs,
- BSC_stat,
- BSC_fstat,
- BSC_lstat,
- BSC_mount,
- BSC_unmount,
- BSC_pathconf,
- BSC_fpathconf,
- BSC_getdirentries,
- BSC_mmap,
- BSC_lseek,
- BSC_truncate,
- BSC_ftruncate,
- BSC_undelete,
- BSC_statv,
- BSC_lstatv,
- BSC_fstatv,
- BSC_mkcomplex,
- BSC_getattrlist,
- BSC_setattrlist,
- BSC_getdirentriesattr,
- BSC_exchangedata,
- BSC_checkuseraccess,
- BSC_searchfs,
- BSC_delete,
- BSC_copyfile,
- BSC_getxattr,
- BSC_fgetxattr,
- BSC_setxattr,
- BSC_fsetxattr,
- BSC_removexattr,
- BSC_fremovexattr,
- BSC_listxattr,
- BSC_flistxattr,
- BSC_fsctl,
- BSC_open_extended,
- BSC_stat_extended,
- BSC_lstat_extended,
- BSC_fstat_extended,
- BSC_chmod_extended,
- BSC_fchmod_extended,
- BSC_access_extended,
- BSC_mkfifo_extended,
- BSC_mkdir_extended,
- BSC_load_shared_file,
- BSC_aio_fsync,
- BSC_aio_return,
- BSC_aio_suspend,
- BSC_aio_suspend_nocancel,
- BSC_aio_cancel,
- BSC_aio_error,
- BSC_aio_read,
- BSC_aio_write,
- BSC_lio_listio,
- BSC_lchown,
- BSC_sendfile,
- BSC_msync,
- BSC_msync_nocancel,
- BSC_fcntl,
- BSC_fcntl_nocancel,
- BSC_ioctl,
- BSC_stat64,
- BSC_fstat64,
- BSC_lstat64,
- BSC_stat64_extended,
- BSC_lstat64_extended,
- BSC_fstat64_extended,
- BSC_getdirentries64,
- BSC_statfs64,
- BSC_fstatfs64,
- BSC_pthread_chdir,
- BSC_pthread_fchdir,
- BSC_getfsstat,
- BSC_getfsstat64,
- 0
-};
-
-
-#define MAX_FILEMGR 512
-
-struct filemgr_call {
- char *fm_name;
-} filemgr_calls[MAX_FILEMGR];
-
-
-int filemgr_call_types[] = {
- FILEMGR_PBGETCATALOGINFO,
- FILEMGR_PBGETCATALOGINFOBULK,
- FILEMGR_PBCREATEFILEUNICODE,
- FILEMGR_PBCREATEDIRECTORYUNICODE,
- FILEMGR_PBCREATEFORK,
- FILEMGR_PBDELETEFORK,
- FILEMGR_PBITERATEFORK,
- FILEMGR_PBOPENFORK,
- FILEMGR_PBREADFORK,
- FILEMGR_PBWRITEFORK,
- FILEMGR_PBALLOCATEFORK,
- FILEMGR_PBDELETEOBJECT,
- FILEMGR_PBEXCHANGEOBJECT,
- FILEMGR_PBGETFORKCBINFO,
- FILEMGR_PBGETVOLUMEINFO,
- FILEMGR_PBMAKEFSREF,
- FILEMGR_PBMAKEFSREFUNICODE,
- FILEMGR_PBMOVEOBJECT,
- FILEMGR_PBOPENITERATOR,
- FILEMGR_PBRENAMEUNICODE,
- FILEMGR_PBSETCATALOGINFO,
- FILEMGR_PBSETVOLUMEINFO,
- FILEMGR_FSREFMAKEPATH,
- FILEMGR_FSPATHMAKEREF,
-
- FILEMGR_PBGETCATINFO,
- FILEMGR_PBGETCATINFOLITE,
- FILEMGR_PBHGETFINFO,
- FILEMGR_PBXGETVOLINFO,
- FILEMGR_PBHCREATE,
- FILEMGR_PBHOPENDF,
- FILEMGR_PBHOPENRF,
- FILEMGR_PBHGETDIRACCESS,
- FILEMGR_PBHSETDIRACCESS,
- FILEMGR_PBHMAPID,
- FILEMGR_PBHMAPNAME,
- FILEMGR_PBCLOSE,
- FILEMGR_PBFLUSHFILE,
- FILEMGR_PBGETEOF,
- FILEMGR_PBSETEOF,
- FILEMGR_PBGETFPOS,
- FILEMGR_PBREAD,
- FILEMGR_PBWRITE,
- FILEMGR_PBGETFCBINFO,
- FILEMGR_PBSETFINFO,
- FILEMGR_PBALLOCATE,
- FILEMGR_PBALLOCCONTIG,
- FILEMGR_PBSETFPOS,
- FILEMGR_PBSETCATINFO,
- FILEMGR_PBGETVOLPARMS,
- FILEMGR_PBSETVINFO,
- FILEMGR_PBMAKEFSSPEC,
- FILEMGR_PBHGETVINFO,
- FILEMGR_PBCREATEFILEIDREF,
- FILEMGR_PBDELETEFILEIDREF,
- FILEMGR_PBRESOLVEFILEIDREF,
- FILEMGR_PBFLUSHVOL,
- FILEMGR_PBHRENAME,
- FILEMGR_PBCATMOVE,
- FILEMGR_PBEXCHANGEFILES,
- FILEMGR_PBHDELETE,
- FILEMGR_PBDIRCREATE,
- FILEMGR_PBCATSEARCH,
- FILEMGR_PBHSETFLOCK,
- FILEMGR_PBHRSTFLOCK,
- FILEMGR_PBLOCKRANGE,
- FILEMGR_PBUNLOCKRANGE,
- 0
-};
-
-
-
-#define MAX_PIDS 256
-int pids[MAX_PIDS];
-
-int num_of_pids = 0;
-int exclude_pids = 0;
-int exclude_default_pids = 1;
-
-
-struct kinfo_proc *kp_buffer = 0;
-int kp_nentries = 0;
-
-#define EVENT_BASE 60000
-
-int num_events = EVENT_BASE;
-
+#define FMT_HFS_update 41
+#define FMT_FLOCK 42
+#define FMT_AT 43
+#define FMT_CHMODAT 44
+#define FMT_OPENAT 45
+#define FMT_RENAMEAT 46
+#define FMT_IOCTL_SYNCCACHE 47
+#define FMT_GUARDED_OPEN 48
#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
-#define DBG_FUNC_MASK 0xfffffffc
-
-double divisor = 0.0; /* Trace divisor converts to microseconds */
-
-int mib[6];
-size_t needed;
-char *my_buffer;
-
-kbufinfo_t bufinfo = {0, 0, 0, 0, 0};
-
-
-/* defines for tracking file descriptor state */
-#define FS_USAGE_FD_SETSIZE 256 /* Initial number of file descriptors per
- thread that we will track */
-
-#define FS_USAGE_NFDBITS (sizeof (unsigned long) * 8)
-#define FS_USAGE_NFDBYTES(n) (((n) / FS_USAGE_NFDBITS) * sizeof (unsigned long))
-
-int trace_enabled = 0;
-int set_remove_flag = 1;
-
-char *RAW_file = (char *)0;
-int RAW_flag = 0;
-int RAW_fd = 0;
-
-uint64_t sample_TOD_secs;
-uint32_t sample_TOD_usecs;
-
-double bias_now = 0.0;
-double start_time = 0.0;
-double end_time = 999999999999.9;
+#pragma mark global state
-void set_numbufs();
-void set_init();
-void set_enable();
-void sample_sc();
-int quit();
+ktrace_session_t s;
+bool BC_flag = false;
+bool RAW_flag = false;
+bool wideflag = false;
+bool include_waited_flag = false;
+bool want_kernel_task = true;
+dispatch_source_t stop_timer, sigquit_source, sigpipe_source, sighup_source, sigterm_source, sigwinch_source;
+uint64_t mach_time_of_first_event;
+uint64_t start_time_ns = 0;
+uint64_t end_time_ns = UINT64_MAX;
+unsigned int columns = 0;
/*
- * signal handlers
+ * Network only or filesystem only output filter
+ * Default of zero means report all activity - no filtering
*/
+#define FILESYS_FILTER 0x01
+#define NETWORK_FILTER 0x02
+#define EXEC_FILTER 0x08
+#define PATHNAME_FILTER 0x10
+#define DISKIO_FILTER 0x20
+#define DEFAULT_DO_NOT_FILTER 0x00
-void leave() /* exit under normal conditions -- INT handler */
-{
- int i;
- void set_enable();
- void set_pidcheck();
- void set_pidexclude();
- void set_remove();
-
- fflush(0);
-
- set_enable(0);
-
- if (exclude_pids == 0) {
- for (i = 0; i < num_of_pids; i++)
- set_pidcheck(pids[i], 0);
- }
- else {
- for (i = 0; i < num_of_pids; i++)
- set_pidexclude(pids[i], 0);
- }
- set_remove();
- exit(0);
-}
-
-
-int
-quit(s)
-char *s;
-{
- if (trace_enabled)
- set_enable(0);
+int filter_mode = DEFAULT_DO_NOT_FILTER;
+bool show_cachehits = false;
- /*
- * This flag is turned off when calling
- * quit() due to a set_remove() failure.
- */
- if (set_remove_flag)
- set_remove();
+#pragma mark syscall lookup table
- fprintf(stderr, "fs_usage: ");
- if (s)
- fprintf(stderr, "%s", s);
+#define MAX_BSD_SYSCALL 526
- exit(1);
-}
+struct bsd_syscall {
+ char *sc_name;
+ int sc_format;
+};
+#define NORMAL_SYSCALL(name) \
+ [BSC_INDEX(BSC_##name)] = {#name, FMT_DEFAULT}
+
+#define SYSCALL(name, format) \
+ [BSC_INDEX(BSC_##name)] = {#name, format}
+
+#define SYSCALL_NAMED(name, displayname, format) \
+ [BSC_INDEX(BSC_##name)] = {#displayname, format}
+
+#define SYSCALL_WITH_NOCANCEL(name, format) \
+ [BSC_INDEX(BSC_##name)] = {#name, format}, \
+ [BSC_INDEX(BSC_##name##_nocancel)] = {#name, format}
+
+const struct bsd_syscall bsd_syscalls[MAX_BSD_SYSCALL] = {
+ SYSCALL(sendfile, FMT_FD), /* this should be changed to FMT_SENDFILE once we add an extended info trace event */
+ SYSCALL_WITH_NOCANCEL(recvmsg, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(sendmsg, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(recvfrom, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(sendto, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(select, FMT_SELECT),
+ SYSCALL_WITH_NOCANCEL(accept, FMT_FD_2),
+ SYSCALL(socket, FMT_SOCKET),
+ SYSCALL_WITH_NOCANCEL(connect, FMT_FD),
+ SYSCALL(bind, FMT_FD),
+ SYSCALL(listen, FMT_FD),
+ SYSCALL(mmap, FMT_MMAP),
+ NORMAL_SYSCALL(socketpair),
+ NORMAL_SYSCALL(getxattr),
+ NORMAL_SYSCALL(setxattr),
+ NORMAL_SYSCALL(removexattr),
+ NORMAL_SYSCALL(listxattr),
+ NORMAL_SYSCALL(stat),
+ NORMAL_SYSCALL(stat64),
+ NORMAL_SYSCALL(stat_extended),
+ SYSCALL_NAMED(stat64_extended, stat_extended64, FMT_DEFAULT), /* should be stat64_extended ? */
+ SYSCALL(mount, FMT_MOUNT),
+ SYSCALL(unmount, FMT_UNMOUNT),
+ NORMAL_SYSCALL(exit),
+ NORMAL_SYSCALL(execve),
+ NORMAL_SYSCALL(posix_spawn),
+ SYSCALL_WITH_NOCANCEL(open, FMT_OPEN),
+ SYSCALL(open_extended, FMT_OPEN),
+ SYSCALL(guarded_open_np, FMT_GUARDED_OPEN),
+ SYSCALL_NAMED(open_dprotected_np, open_dprotected, FMT_OPEN),
+ SYSCALL(guarded_open_dprotected_np, FMT_GUARDED_OPEN),
+ SYSCALL(dup, FMT_FD_2),
+ SYSCALL(dup2, FMT_FD_2),
+ SYSCALL_WITH_NOCANCEL(close, FMT_FD),
+ SYSCALL(guarded_close_np, FMT_FD),
+ SYSCALL_WITH_NOCANCEL(read, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(write, FMT_FD_IO),
+ SYSCALL(guarded_write_np, FMT_FD_IO),
+ SYSCALL(guarded_pwrite_np, FMT_PREAD),
+ SYSCALL(guarded_writev_np, FMT_FD_IO),
+ SYSCALL(fgetxattr, FMT_FD),
+ SYSCALL(fsetxattr, FMT_FD),
+ SYSCALL(fremovexattr, FMT_FD),
+ SYSCALL(flistxattr, FMT_FD),
+ SYSCALL(fstat, FMT_FD),
+ SYSCALL(fstat64, FMT_FD),
+ SYSCALL(fstat_extended, FMT_FD),
+ SYSCALL(fstat64_extended, FMT_FD),
+ NORMAL_SYSCALL(lstat),
+ NORMAL_SYSCALL(lstat64),
+ NORMAL_SYSCALL(lstat_extended),
+ SYSCALL_NAMED(lstat64_extended, lstat_extended64, FMT_DEFAULT),
+ NORMAL_SYSCALL(link),
+ NORMAL_SYSCALL(unlink),
+ NORMAL_SYSCALL(mknod),
+ SYSCALL(umask, FMT_UMASK),
+ SYSCALL(umask_extended, FMT_UMASK),
+ SYSCALL(chmod, FMT_CHMOD),
+ SYSCALL(chmod_extended, FMT_CHMOD_EXT),
+ SYSCALL(fchmod, FMT_FCHMOD),
+ SYSCALL(fchmod_extended, FMT_FCHMOD_EXT),
+ NORMAL_SYSCALL(chown),
+ NORMAL_SYSCALL(lchown),
+ SYSCALL(fchown, FMT_FD),
+ SYSCALL(access, FMT_ACCESS),
+ NORMAL_SYSCALL(access_extended),
+ NORMAL_SYSCALL(chdir),
+ NORMAL_SYSCALL(pthread_chdir),
+ NORMAL_SYSCALL(chroot),
+ NORMAL_SYSCALL(utimes),
+ SYSCALL_NAMED(delete, delete-Carbon, FMT_DEFAULT),
+ NORMAL_SYSCALL(undelete),
+ NORMAL_SYSCALL(revoke),
+ NORMAL_SYSCALL(fsctl),
+ SYSCALL(ffsctl, FMT_FD),
+ SYSCALL(chflags, FMT_CHFLAGS),
+ SYSCALL(fchflags, FMT_FCHFLAGS),
+ SYSCALL(fchdir, FMT_FD),
+ SYSCALL(pthread_fchdir, FMT_FD),
+ SYSCALL(futimes, FMT_FD),
+ NORMAL_SYSCALL(sync),
+ NORMAL_SYSCALL(symlink),
+ NORMAL_SYSCALL(readlink),
+ SYSCALL_WITH_NOCANCEL(fsync, FMT_FD),
+ SYSCALL(fdatasync, FMT_FD),
+ SYSCALL_WITH_NOCANCEL(readv, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(writev, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(pread, FMT_PREAD),
+ SYSCALL_WITH_NOCANCEL(pwrite, FMT_PREAD),
+ NORMAL_SYSCALL(mkdir),
+ NORMAL_SYSCALL(mkdir_extended),
+ NORMAL_SYSCALL(mkfifo),
+ NORMAL_SYSCALL(mkfifo_extended),
+ NORMAL_SYSCALL(rmdir),
+ NORMAL_SYSCALL(statfs),
+ NORMAL_SYSCALL(statfs64),
+ NORMAL_SYSCALL(getfsstat),
+ NORMAL_SYSCALL(getfsstat64),
+ SYSCALL(fstatfs, FMT_FD),
+ SYSCALL(fstatfs64, FMT_FD),
+ NORMAL_SYSCALL(pathconf),
+ SYSCALL(fpathconf, FMT_FD),
+ SYSCALL(getdirentries, FMT_FD_IO),
+ SYSCALL(getdirentries64, FMT_FD_IO),
+ SYSCALL(lseek, FMT_LSEEK),
+ SYSCALL(truncate, FMT_TRUNC),
+ SYSCALL(ftruncate, FMT_FTRUNC),
+ SYSCALL(flock, FMT_FLOCK),
+ NORMAL_SYSCALL(getattrlist),
+ NORMAL_SYSCALL(setattrlist),
+ SYSCALL(fgetattrlist, FMT_FD),
+ SYSCALL(fsetattrlist, FMT_FD),
+ SYSCALL(getdirentriesattr, FMT_FD),
+ NORMAL_SYSCALL(exchangedata),
+ NORMAL_SYSCALL(rename),
+ NORMAL_SYSCALL(copyfile),
+ NORMAL_SYSCALL(checkuseraccess),
+ NORMAL_SYSCALL(searchfs),
+ SYSCALL(aio_fsync, FMT_AIO_FSYNC),
+ SYSCALL(aio_return, FMT_AIO_RETURN),
+ SYSCALL_WITH_NOCANCEL(aio_suspend, FMT_AIO_SUSPEND),
+ SYSCALL(aio_cancel, FMT_AIO_CANCEL),
+ SYSCALL(aio_error, FMT_AIO),
+ SYSCALL(aio_read, FMT_AIO),
+ SYSCALL(aio_write, FMT_AIO),
+ SYSCALL(lio_listio, FMT_LIO_LISTIO),
+ SYSCALL_WITH_NOCANCEL(msync, FMT_MSYNC),
+ SYSCALL_WITH_NOCANCEL(fcntl, FMT_FCNTL),
+ SYSCALL(ioctl, FMT_IOCTL),
+ NORMAL_SYSCALL(fsgetpath),
+ NORMAL_SYSCALL(getattrlistbulk),
+ SYSCALL_WITH_NOCANCEL(openat, FMT_OPENAT), /* open_nocancel() was previously shown as "open_nocanel" (note spelling) */
+ SYSCALL(renameat, FMT_RENAMEAT),
+ SYSCALL(chmodat, FMT_CHMODAT),
+ SYSCALL(chownat, FMT_AT),
+ SYSCALL(fstatat, FMT_AT),
+ SYSCALL(fstatat64, FMT_AT),
+ SYSCALL(linkat, FMT_AT),
+ SYSCALL(unlinkat, FMT_AT),
+ SYSCALL(readlinkat, FMT_AT),
+ SYSCALL(symlinkat, FMT_AT),
+ SYSCALL(mkdirat, FMT_AT),
+ SYSCALL(getattrlistat, FMT_AT),
+};
-void get_screenwidth()
+static void
+get_screenwidth(void)
{
- struct winsize size;
+ struct winsize size;
columns = MAXCOLS;
- if (isatty(1)) {
- if (ioctl(1, TIOCGWINSZ, &size) != -1) {
- columns = size.ws_col;
+ if (isatty(STDOUT_FILENO)) {
+ if (ioctl(1, TIOCGWINSZ, &size) != -1) {
+ columns = size.ws_col;
if (columns > MAXWIDTH)
- columns = MAXWIDTH;
+ columns = MAXWIDTH;
}
}
}
-
-void sigwinch()
-{
- if (!wideflag)
- get_screenwidth();
-}
-
-
-void getdivisor()
+static uint64_t
+mach_to_nano(uint64_t mach)
{
- struct mach_timebase_info mti;
-
- mach_timebase_info(&mti);
+ uint64_t nanoseconds = 0;
+ os_assert(ktrace_convert_timestamp_to_nanoseconds(s, mach, &nanoseconds) == 0);
- divisor = ((double)mti.denom / (double)mti.numer) * 1000;
+ return nanoseconds;
}
+static void
+exit_usage(void)
+{
+ const char *myname;
-int
-exit_usage(char *myname) {
+ myname = getprogname();
- fprintf(stderr, "Usage: %s [-e] [-w] [-f mode] [-R rawfile [-S start_time] [-E end_time]] [pid | cmd [pid | cmd]....]\n", myname);
+ 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);
fprintf(stderr, " -e exclude the specified list of pids from the sample\n");
fprintf(stderr, " and exclude fs_usage by default\n");
fprintf(stderr, " -w force wider, detailed, output\n");
- fprintf(stderr, " -f Output is based on the mode provided\n");
- fprintf(stderr, " mode = \"network\" Show only network related output\n");
- fprintf(stderr, " mode = \"filesys\" Show only file system related output\n");
- fprintf(stderr, " mode = \"pathname\" Show only pathname related output\n");
- fprintf(stderr, " mode = \"exec\" Show only execs\n");
- fprintf(stderr, " mode = \"cachehit\" In addition, show cachehits\n");
+ fprintf(stderr, " -f output is based on the mode provided\n");
+ fprintf(stderr, " mode = \"network\" Show network-related events\n");
+ fprintf(stderr, " mode = \"filesys\" Show filesystem-related events\n");
+ fprintf(stderr, " mode = \"pathname\" Show only pathname-related events\n");
+ fprintf(stderr, " mode = \"exec\" Show only exec and spawn events\n");
+ fprintf(stderr, " mode = \"diskio\" Show only disk I/O events\n");
+ fprintf(stderr, " mode = \"cachehit\" In addition, show cache hits\n");
+ fprintf(stderr, " -b annotate disk I/O events with BootCache info (if available)\n");
+ fprintf(stderr, " -t specifies timeout in seconds (for use in automated tools)\n");
fprintf(stderr, " -R specifies a raw trace file to process\n");
fprintf(stderr, " -S if -R is specified, selects a start point in microseconds\n");
fprintf(stderr, " -E if -R is specified, selects an end point in microseconds\n");
fprintf(stderr, " pid selects process(s) to sample\n");
fprintf(stderr, " cmd selects process(s) matching command string to sample\n");
- fprintf(stderr, "\n%s will handle a maximum list of %d pids.\n\n", myname, MAX_PIDS);
fprintf(stderr, "By default (no options) the following processes are excluded from the output:\n");
fprintf(stderr, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");
exit(1);
}
+static void fs_usage_cleanup(const char *message)
+{
+ if (s){
+ ktrace_session_destroy(s);
+ }
-int filemgr_index(type) {
+ fprintf(stderr, "Cleaning up tracing state because of %s\n", message);
+}
- if (type & 0x10000)
- return (((type >> 2) & 0x3fff) + 256);
+int
+main(int argc, char *argv[])
+{
+ char ch;
+ int rv;
+ bool exclude_pids = false;
+ uint64_t time_limit_ns = 0;
- return (((type >> 2) & 0x3fff));
-}
+ os_set_crash_callback(&fs_usage_cleanup);
+ get_screenwidth();
-void init_tables(void)
-{ int i;
- int type;
- int code;
+ s = ktrace_session_create();
+ os_assert(s != NULL);
+ (void)ktrace_ignore_process_filter_for_event(s, P_WrData);
+ (void)ktrace_ignore_process_filter_for_event(s, P_RdData);
+ (void)ktrace_ignore_process_filter_for_event(s, P_WrMeta);
+ (void)ktrace_ignore_process_filter_for_event(s, P_RdMeta);
+ (void)ktrace_ignore_process_filter_for_event(s, P_PgOut);
+ (void)ktrace_ignore_process_filter_for_event(s, P_PgIn);
+
+ while ((ch = getopt(argc, argv, "bewf:R:S:E:t:W")) != -1) {
+ switch (ch) {
+ case 'e':
+ exclude_pids = true;
+ break;
+ case 'w':
+ wideflag = 1;
+ columns = MAX_WIDE_MODE_COLS;
+ break;
- for (i = 0; i < MAX_BSD_SYSCALL; i++) {
- bsd_syscalls[i].sc_name = NULL;
- bsd_syscalls[i].sc_format = FMT_DEFAULT;
- }
+ case 'W':
+ include_waited_flag = true;
+ break;
- for (i = 0; i < MAX_FILEMGR; i++) {
- filemgr_calls[i].fm_name = NULL;
- }
+ case 'f':
+ if (!strcmp(optarg, "network"))
+ filter_mode |= NETWORK_FILTER;
+ else if (!strcmp(optarg, "filesys"))
+ filter_mode |= FILESYS_FILTER;
+ else if (!strcmp(optarg, "cachehit"))
+ show_cachehits = true;
+ else if (!strcmp(optarg, "exec"))
+ filter_mode |= EXEC_FILTER;
+ else if (!strcmp(optarg, "pathname"))
+ filter_mode |= PATHNAME_FILTER;
+ else if (!strcmp(optarg, "diskio"))
+ filter_mode |= DISKIO_FILTER;
- for (i = 0; (type = bsd_syscall_types[i]); i++) {
+ break;
- code = BSC_INDEX(type);
+ case 'b':
+ BC_flag = true;
+ break;
- if (code >= MAX_BSD_SYSCALL) {
- printf("BSD syscall init (%x): type exceeds table size\n", type);
- continue;
- }
- switch (type) {
+ case 't':
+ time_limit_ns = (uint64_t)(NSEC_PER_SEC * atof(optarg));
+ if (time_limit_ns == 0) {
+ fprintf(stderr, "ERROR: could not set time limit to %s\n",
+ optarg);
+ exit(1);
+ }
+ break;
- case BSC_sendfile:
- bsd_syscalls[code].sc_name = "sendfile";
- bsd_syscalls[code].sc_format = FMT_FD; /* this should be changed to FMT_SENDFILE */
- break; /* once we add an extended info trace event */
-
- case BSC_recvmsg:
- case BSC_recvmsg_nocancel:
- bsd_syscalls[code].sc_name = "recvmsg";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_sendmsg:
- case BSC_sendmsg_nocancel:
- bsd_syscalls[code].sc_name = "sendmsg";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_recvfrom:
- case BSC_recvfrom_nocancel:
- bsd_syscalls[code].sc_name = "recvfrom";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_sendto:
- case BSC_sendto_nocancel:
- bsd_syscalls[code].sc_name = "sendto";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_select:
- case BSC_select_nocancel:
- bsd_syscalls[code].sc_name = "select";
- bsd_syscalls[code].sc_format = FMT_SELECT;
- break;
-
- case BSC_accept:
- case BSC_accept_nocancel:
- bsd_syscalls[code].sc_name = "accept";
- bsd_syscalls[code].sc_format = FMT_FD_2;
- break;
-
- case BSC_socket:
- bsd_syscalls[code].sc_name = "socket";
- bsd_syscalls[code].sc_format = FMT_SOCKET;
- break;
-
- case BSC_connect:
- case BSC_connect_nocancel:
- bsd_syscalls[code].sc_name = "connect";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_bind:
- bsd_syscalls[code].sc_name = "bind";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_listen:
- bsd_syscalls[code].sc_name = "listen";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_mmap:
- bsd_syscalls[code].sc_name = "mmap";
- bsd_syscalls[code].sc_format = FMT_MMAP;
- break;
-
- case BSC_socketpair:
- bsd_syscalls[code].sc_name = "socketpair";
- break;
-
- case BSC_getxattr:
- bsd_syscalls[code].sc_name = "getxattr";
- break;
-
- case BSC_setxattr:
- bsd_syscalls[code].sc_name = "setxattr";
- break;
-
- case BSC_removexattr:
- bsd_syscalls[code].sc_name = "removexattr";
- break;
-
- case BSC_listxattr:
- bsd_syscalls[code].sc_name = "listxattr";
- break;
-
- case BSC_stat:
- bsd_syscalls[code].sc_name = "stat";
- break;
-
- case BSC_stat64:
- bsd_syscalls[code].sc_name = "stat64";
- break;
-
- case BSC_stat_extended:
- bsd_syscalls[code].sc_name = "stat_extended";
- break;
-
- case BSC_stat64_extended:
- bsd_syscalls[code].sc_name = "stat_extended64";
- break;
-
- case BSC_mount:
- bsd_syscalls[code].sc_name = "mount";
- bsd_syscalls[code].sc_format = FMT_MOUNT;
- break;
-
- case BSC_unmount:
- bsd_syscalls[code].sc_name = "unmount";
- bsd_syscalls[code].sc_format = FMT_UNMOUNT;
- break;
-
- case BSC_exit:
- bsd_syscalls[code].sc_name = "exit";
- break;
-
- case BSC_execve:
- bsd_syscalls[code].sc_name = "execve";
- break;
-
- case BSC_posix_spawn:
- bsd_syscalls[code].sc_name = "posix_spawn";
- break;
-
- case BSC_load_shared_file:
- bsd_syscalls[code].sc_name = "load_sf";
- break;
-
- case BSC_open:
- case BSC_open_nocancel:
- bsd_syscalls[code].sc_name = "open";
- bsd_syscalls[code].sc_format = FMT_OPEN;
- break;
-
- case BSC_open_extended:
- bsd_syscalls[code].sc_name = "open_extended";
- bsd_syscalls[code].sc_format = FMT_OPEN;
- break;
-
- case BSC_dup:
- bsd_syscalls[code].sc_name = "dup";
- bsd_syscalls[code].sc_format = FMT_FD_2;
- break;
-
- case BSC_dup2:
- bsd_syscalls[code].sc_name = "dup2";
- bsd_syscalls[code].sc_format = FMT_FD_2;
- break;
-
- case BSC_close:
- case BSC_close_nocancel:
- bsd_syscalls[code].sc_name = "close";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_read:
- case BSC_read_nocancel:
- bsd_syscalls[code].sc_name = "read";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_write:
- case BSC_write_nocancel:
- bsd_syscalls[code].sc_name = "write";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_fgetxattr:
- bsd_syscalls[code].sc_name = "fgetxattr";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_fsetxattr:
- bsd_syscalls[code].sc_name = "fsetxattr";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_fremovexattr:
- bsd_syscalls[code].sc_name = "fremovexattr";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_flistxattr:
- bsd_syscalls[code].sc_name = "flistxattr";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_fstat:
- bsd_syscalls[code].sc_name = "fstat";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_fstat64:
- bsd_syscalls[code].sc_name = "fstat64";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_fstat_extended:
- bsd_syscalls[code].sc_name = "fstat_extended";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_fstat64_extended:
- bsd_syscalls[code].sc_name = "fstat64_extended";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_lstat:
- bsd_syscalls[code].sc_name = "lstat";
- break;
-
- case BSC_lstat64:
- bsd_syscalls[code].sc_name = "lstat64";
- break;
-
- case BSC_lstat_extended:
- bsd_syscalls[code].sc_name = "lstat_extended";
- break;
-
- case BSC_lstat64_extended:
- bsd_syscalls[code].sc_name = "lstat_extended64";
- break;
-
- case BSC_lstatv:
- bsd_syscalls[code].sc_name = "lstatv";
- break;
-
- case BSC_link:
- bsd_syscalls[code].sc_name = "link";
- break;
-
- case BSC_unlink:
- bsd_syscalls[code].sc_name = "unlink";
- break;
-
- case BSC_mknod:
- bsd_syscalls[code].sc_name = "mknod";
- break;
-
- case BSC_umask:
- bsd_syscalls[code].sc_name = "umask";
- bsd_syscalls[code].sc_format = FMT_UMASK;
- break;
-
- case BSC_chmod:
- bsd_syscalls[code].sc_name = "chmod";
- bsd_syscalls[code].sc_format = FMT_CHMOD;
- break;
-
- case BSC_chmod_extended:
- bsd_syscalls[code].sc_name = "chmod_extended";
- bsd_syscalls[code].sc_format = FMT_CHMOD_EXT;
- break;
-
- case BSC_fchmod:
- bsd_syscalls[code].sc_name = "fchmod";
- bsd_syscalls[code].sc_format = FMT_FCHMOD;
- break;
-
- case BSC_fchmod_extended:
- bsd_syscalls[code].sc_name = "fchmod_extended";
- bsd_syscalls[code].sc_format = FMT_FCHMOD_EXT;
- break;
-
- case BSC_chown:
- bsd_syscalls[code].sc_name = "chown";
- break;
-
- case BSC_lchown:
- bsd_syscalls[code].sc_name = "lchown";
- break;
-
- case BSC_fchown:
- bsd_syscalls[code].sc_name = "fchown";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_access:
- bsd_syscalls[code].sc_name = "access";
- bsd_syscalls[code].sc_format = FMT_ACCESS;
- break;
-
- case BSC_access_extended:
- bsd_syscalls[code].sc_name = "access_extended";
- break;
-
- case BSC_chdir:
- bsd_syscalls[code].sc_name = "chdir";
- break;
-
- case BSC_pthread_chdir:
- bsd_syscalls[code].sc_name = "pthread_chdir";
- break;
-
- case BSC_chroot:
- bsd_syscalls[code].sc_name = "chroot";
- break;
-
- case BSC_utimes:
- bsd_syscalls[code].sc_name = "utimes";
- break;
-
- case BSC_delete:
- bsd_syscalls[code].sc_name = "delete-Carbon";
- break;
-
- case BSC_undelete:
- bsd_syscalls[code].sc_name = "undelete";
- break;
-
- case BSC_revoke:
- bsd_syscalls[code].sc_name = "revoke";
- break;
-
- case BSC_fsctl:
- bsd_syscalls[code].sc_name = "fsctl";
- break;
-
- case BSC_chflags:
- bsd_syscalls[code].sc_name = "chflags";
- bsd_syscalls[code].sc_format = FMT_CHFLAGS;
- break;
-
- case BSC_fchflags:
- bsd_syscalls[code].sc_name = "fchflags";
- bsd_syscalls[code].sc_format = FMT_FCHFLAGS;
- break;
-
- case BSC_fchdir:
- bsd_syscalls[code].sc_name = "fchdir";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_pthread_fchdir:
- bsd_syscalls[code].sc_name = "pthread_fchdir";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_futimes:
- bsd_syscalls[code].sc_name = "futimes";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_sync:
- bsd_syscalls[code].sc_name = "sync";
- break;
-
- case BSC_symlink:
- bsd_syscalls[code].sc_name = "symlink";
- break;
-
- case BSC_readlink:
- bsd_syscalls[code].sc_name = "readlink";
- break;
-
- case BSC_fsync:
- case BSC_fsync_nocancel:
- bsd_syscalls[code].sc_name = "fsync";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_readv:
- case BSC_readv_nocancel:
- bsd_syscalls[code].sc_name = "readv";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_writev:
- case BSC_writev_nocancel:
- bsd_syscalls[code].sc_name = "writev";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_pread:
- case BSC_pread_nocancel:
- bsd_syscalls[code].sc_name = "pread";
- bsd_syscalls[code].sc_format = FMT_PREAD;
- break;
-
- case BSC_pwrite:
- case BSC_pwrite_nocancel:
- bsd_syscalls[code].sc_name = "pwrite";
- bsd_syscalls[code].sc_format = FMT_PREAD;
- break;
-
- case BSC_mkdir:
- bsd_syscalls[code].sc_name = "mkdir";
- break;
-
- case BSC_mkdir_extended:
- bsd_syscalls[code].sc_name = "mkdir_extended";
- break;
-
- case BSC_mkfifo:
- bsd_syscalls[code].sc_name = "mkfifo";
- break;
-
- case BSC_mkfifo_extended:
- bsd_syscalls[code].sc_name = "mkfifo_extended";
- break;
-
- case BSC_rmdir:
- bsd_syscalls[code].sc_name = "rmdir";
- break;
-
- case BSC_statfs:
- bsd_syscalls[code].sc_name = "statfs";
- break;
-
- case BSC_statfs64:
- bsd_syscalls[code].sc_name = "statfs64";
- break;
-
- case BSC_getfsstat:
- bsd_syscalls[code].sc_name = "getfsstat";
- break;
-
- case BSC_getfsstat64:
- bsd_syscalls[code].sc_name = "getfsstat64";
- break;
-
- case BSC_fstatfs:
- bsd_syscalls[code].sc_name = "fstatfs";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_fstatfs64:
- bsd_syscalls[code].sc_name = "fstatfs64";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_pathconf:
- bsd_syscalls[code].sc_name = "pathconf";
- break;
-
- case BSC_fpathconf:
- bsd_syscalls[code].sc_name = "fpathconf";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_getdirentries:
- bsd_syscalls[code].sc_name = "getdirentries";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_getdirentries64:
- bsd_syscalls[code].sc_name = "getdirentries64";
- bsd_syscalls[code].sc_format = FMT_FD_IO;
- break;
-
- case BSC_lseek:
- bsd_syscalls[code].sc_name = "lseek";
- bsd_syscalls[code].sc_format = FMT_LSEEK;
- break;
-
- case BSC_truncate:
- bsd_syscalls[code].sc_name = "truncate";
- bsd_syscalls[code].sc_format = FMT_TRUNC;
- break;
-
- case BSC_ftruncate:
- bsd_syscalls[code].sc_name = "ftruncate";
- bsd_syscalls[code].sc_format = FMT_FTRUNC;
- break;
-
- case BSC_statv:
- bsd_syscalls[code].sc_name = "statv";
- break;
-
- case BSC_fstatv:
- bsd_syscalls[code].sc_name = "fstatv";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_mkcomplex:
- bsd_syscalls[code].sc_name = "mkcomplex";
- break;
-
- case BSC_getattrlist:
- bsd_syscalls[code].sc_name = "getattrlist";
- break;
-
- case BSC_setattrlist:
- bsd_syscalls[code].sc_name = "setattrlist";
- break;
-
- case BSC_getdirentriesattr:
- bsd_syscalls[code].sc_name = "getdirentriesattr";
- bsd_syscalls[code].sc_format = FMT_FD;
- break;
-
- case BSC_exchangedata:
- bsd_syscalls[code].sc_name = "exchangedata";
- break;
-
- case BSC_rename:
- bsd_syscalls[code].sc_name = "rename";
- break;
-
- case BSC_copyfile:
- bsd_syscalls[code].sc_name = "copyfile";
- break;
-
- case BSC_checkuseraccess:
- bsd_syscalls[code].sc_name = "checkuseraccess";
- break;
-
- case BSC_searchfs:
- bsd_syscalls[code].sc_name = "searchfs";
- break;
-
- case BSC_aio_fsync:
- bsd_syscalls[code].sc_name = "aio_fsync";
- bsd_syscalls[code].sc_format = FMT_AIO_FSYNC;
- break;
-
- case BSC_aio_return:
- bsd_syscalls[code].sc_name = "aio_return";
- bsd_syscalls[code].sc_format = FMT_AIO_RETURN;
- break;
-
- case BSC_aio_suspend:
- case BSC_aio_suspend_nocancel:
- bsd_syscalls[code].sc_name = "aio_suspend";
- bsd_syscalls[code].sc_format = FMT_AIO_SUSPEND;
- break;
-
- case BSC_aio_cancel:
- bsd_syscalls[code].sc_name = "aio_cancel";
- bsd_syscalls[code].sc_format = FMT_AIO_CANCEL;
- break;
-
- case BSC_aio_error:
- bsd_syscalls[code].sc_name = "aio_error";
- bsd_syscalls[code].sc_format = FMT_AIO;
- break;
-
- case BSC_aio_read:
- bsd_syscalls[code].sc_name = "aio_read";
- bsd_syscalls[code].sc_format = FMT_AIO;
- break;
-
- case BSC_aio_write:
- bsd_syscalls[code].sc_name = "aio_write";
- bsd_syscalls[code].sc_format = FMT_AIO;
- break;
-
- case BSC_lio_listio:
- bsd_syscalls[code].sc_name = "lio_listio";
- bsd_syscalls[code].sc_format = FMT_LIO_LISTIO;
- break;
-
- case BSC_msync:
- case BSC_msync_nocancel:
- bsd_syscalls[code].sc_name = "msync";
- bsd_syscalls[code].sc_format = FMT_MSYNC;
- break;
-
- case BSC_fcntl:
- case BSC_fcntl_nocancel:
- bsd_syscalls[code].sc_name = "fcntl";
- bsd_syscalls[code].sc_format = FMT_FCNTL;
- break;
-
- case BSC_ioctl:
- bsd_syscalls[code].sc_name = "ioctl";
- bsd_syscalls[code].sc_format = FMT_IOCTL;
- break;
- }
- }
+ case 'R':
+ RAW_flag = true;
+ rv = ktrace_set_file(s, optarg);
+ if (rv) {
+ fprintf(stderr, "ERROR: reading trace from '%s' failed (%s)\n", optarg, strerror(errno));
+ exit(1);
+ }
+ break;
- for (i = 0; (type = filemgr_call_types[i]); i++) {
- char * p;
+ case 'S':
+ start_time_ns = NSEC_PER_SEC * atof(optarg);
+ break;
- code = filemgr_index(type);
+ case 'E':
+ end_time_ns = NSEC_PER_SEC * atof(optarg);
+ break;
- if (code >= MAX_FILEMGR) {
- printf("FILEMGR call init (%x): type exceeds table size\n", type);
- continue;
+ default:
+ exit_usage();
}
- switch (type) {
+ }
- case FILEMGR_PBGETCATALOGINFO:
- p = "GetCatalogInfo";
- break;
+ argc -= optind;
+ argv += optind;
- case FILEMGR_PBGETCATALOGINFOBULK:
- p = "GetCatalogInfoBulk";
- break;
+ if (time_limit_ns > 0 && RAW_flag) {
+ fprintf(stderr, "NOTE: time limit ignored when a raw file is specified\n");
+ time_limit_ns = 0;
+ }
- case FILEMGR_PBCREATEFILEUNICODE:
- p = "CreateFileUnicode";
- break;
+ if (!RAW_flag) {
+ if (geteuid() != 0) {
+ fprintf(stderr, "'fs_usage' must be run as root...\n");
+ exit(1);
+ }
- case FILEMGR_PBCREATEDIRECTORYUNICODE:
- p = "CreateDirectoryUnicode";
- break;
+ /*
+ * ktrace can't both *in*clude and *ex*clude pids, so: if we are
+ * already excluding pids, or if we are not explicitly including
+ * or excluding any pids, then exclude the defaults.
+ *
+ * if on the other hand we are explicitly including pids, we'll
+ * filter the defaults out naturally.
+ */
+ if (exclude_pids || argc == 0) {
+ ktrace_exclude_process(s, "fs_usage");
+ ktrace_exclude_process(s, "Terminal");
+ ktrace_exclude_process(s, "telnetd");
+ ktrace_exclude_process(s, "telnet");
+ ktrace_exclude_process(s, "sshd");
+ ktrace_exclude_process(s, "rlogind");
+ ktrace_exclude_process(s, "tcsh");
+ ktrace_exclude_process(s, "csh");
+ ktrace_exclude_process(s, "sh");
+ ktrace_exclude_process(s, "zsh");
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ ktrace_exclude_process(s, "dropbear");
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+ }
+ }
- case FILEMGR_PBCREATEFORK:
- p = "PBCreateFork";
- break;
+ /*
+ * If we're *in*cluding processes, also *in*clude the kernel_task, which
+ * issues trace points when disk I/Os complete. But set a flag for us to
+ * avoid showing events attributed to the kernel_task.
+ *
+ * If the user actually wants to those events, we'll change that flag in
+ * the loop below.
+ */
+ if (argc > 0 && !exclude_pids) {
+ ktrace_filter_pid(s, 0);
+ want_kernel_task = false;
+ }
- case FILEMGR_PBDELETEFORK:
- p = "PBDeleteFork";
- break;
+ /*
+ * Process the list of specified pids, and in/exclude them as
+ * appropriate.
+ */
+ while (argc > 0) {
+ pid_t pid;
+ char *name;
+ char *endptr;
- case FILEMGR_PBITERATEFORK:
- p = "PBIterateFork";
- break;
+ name = argv[0];
+ pid = (pid_t)strtoul(name, &endptr, 10);
- case FILEMGR_PBOPENFORK:
- p = "PBOpenFork";
- break;
+ if (*name != '\0' && *endptr == '\0') {
+ if (exclude_pids) {
+ rv = ktrace_exclude_pid(s, pid);
+ } else {
+ if (pid == 0)
+ want_kernel_task = true;
+ else
+ rv = ktrace_filter_pid(s, pid);
+ }
+ } else {
+ if (exclude_pids) {
+ rv = ktrace_exclude_process(s, name);
+ } else {
+ if (!strcmp(name, "kernel_task"))
+ want_kernel_task = true;
+ else
+ rv = ktrace_filter_process(s, name);
+ }
+ }
- case FILEMGR_PBREADFORK:
- p = "PBReadFork";
- break;
+ if (rv == EINVAL) {
+ fprintf(stderr, "ERROR: cannot both include and exclude simultaneously\n");
+ exit(1);
+ } else {
+ os_assert(!rv);
+ }
- case FILEMGR_PBWRITEFORK:
- p = "PBWriteFork";
- break;
+ argc--;
+ argv++;
+ }
- case FILEMGR_PBALLOCATEFORK:
- p = "PBAllocateFork";
- break;
+ /* provides SIGINT, SIGHUP, SIGPIPE, SIGTERM handlers */
+ ktrace_set_signal_handler(s);
- case FILEMGR_PBDELETEOBJECT:
- p = "PBDeleteObject";
- break;
+ ktrace_set_completion_handler(s, ^{
+ exit(0);
+ });
- case FILEMGR_PBEXCHANGEOBJECT:
- p = "PBExchangeObject";
- break;
+ signal(SIGWINCH, SIG_IGN);
+ sigwinch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGWINCH, 0, dispatch_get_main_queue());
+ dispatch_source_set_event_handler(sigwinch_source, ^{
+ if (!wideflag)
+ get_screenwidth();
+ });
+ dispatch_activate(sigwinch_source);
- case FILEMGR_PBGETFORKCBINFO:
- p = "PBGetForkCBInfo";
- break;
+ init_shared_cache_mapping();
- case FILEMGR_PBGETVOLUMEINFO:
- p = "PBGetVolumeInfo";
- break;
-
- case FILEMGR_PBMAKEFSREF:
- p = "PBMakeFSRef";
- break;
+ cache_disk_names();
- case FILEMGR_PBMAKEFSREFUNICODE:
- p = "PBMakeFSRefUnicode";
- break;
+ setup_ktrace_callbacks();
- case FILEMGR_PBMOVEOBJECT:
- p = "PBMoveObject";
- break;
+ ktrace_set_dropped_events_handler(s, ^{
+ fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly\n");
- case FILEMGR_PBOPENITERATOR:
- p = "PBOpenIterator";
- break;
+ /* clear any state that is now potentially invalid */
- case FILEMGR_PBRENAMEUNICODE:
- p = "PBRenameUnicode";
- break;
+ event_delete_all();
+ fd_clear_all();
+ meta_delete_all();
+ });
- case FILEMGR_PBSETCATALOGINFO:
- p = "SetCatalogInfo";
- break;
+ ktrace_set_default_event_names_enabled(KTRACE_FEATURE_DISABLED);
+ ktrace_set_execnames_enabled(s, KTRACE_FEATURE_LAZY);
+ ktrace_set_vnode_paths_enabled(s, true);
+ /* no need to symbolicate addresses */
+ ktrace_set_uuid_map_enabled(s, KTRACE_FEATURE_DISABLED);
- case FILEMGR_PBSETVOLUMEINFO:
- p = "SetVolumeInfo";
- break;
+ rv = ktrace_start(s, dispatch_get_main_queue());
- case FILEMGR_FSREFMAKEPATH:
- p = "FSRefMakePath";
- break;
+ if (rv) {
+ perror("ktrace_start");
+ exit(1);
+ }
- case FILEMGR_FSPATHMAKEREF:
- p = "FSPathMakeRef";
- break;
+ if (time_limit_ns > 0) {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, time_limit_ns),
+ dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
+ ^{
+ ktrace_end(s, 0);
+ });
+ }
- case FILEMGR_PBGETCATINFO:
- p = "GetCatInfo";
- break;
+ dispatch_main();
- case FILEMGR_PBGETCATINFOLITE:
- p = "GetCatInfoLite";
- break;
+ return 0;
+}
- case FILEMGR_PBHGETFINFO:
- p = "PBHGetFInfo";
- break;
+void
+setup_ktrace_callbacks(void)
+{
+ ktrace_events_subclass(s, DBG_MACH, DBG_MACH_EXCP_SC, ^(ktrace_event_t event) {
+ int type;
- case FILEMGR_PBXGETVOLINFO:
- p = "PBXGetVolInfo";
- break;
+ type = event->debugid & KDBG_EVENTID_MASK;
- case FILEMGR_PBHCREATE:
- p = "PBHCreate";
- break;
+ if (type == MSC_map_fd) {
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ event_exit("map_fd", type, event, FMT_FD);
+ }
+ }
+ });
- case FILEMGR_PBHOPENDF:
- p = "PBHOpenDF";
- break;
+ ktrace_events_subclass(s, DBG_MACH, DBG_MACH_VM, ^(ktrace_event_t event) {
+ th_info_t ti;
+ unsigned int type;
- case FILEMGR_PBHOPENRF:
- p = "PBHOpenRF";
- break;
+ type = event->debugid & KDBG_EVENTID_MASK;
- case FILEMGR_PBHGETDIRACCESS:
- p = "PBHGetDirAccess";
- break;
+ if (type != MACH_pageout && type != MACH_vmfault)
+ return;
- case FILEMGR_PBHSETDIRACCESS:
- p = "PBHSetDirAccess";
- break;
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ switch (type) {
+ case MACH_pageout:
+ if (event->arg2)
+ event_exit("PAGE_OUT_ANON", type, event, FMT_PGOUT);
+ else
+ event_exit("PAGE_OUT_FILE", type, event, FMT_PGOUT);
+
+ break;
+
+ case MACH_vmfault:
+ if (event->arg4 == DBG_PAGEIN_FAULT)
+ event_exit("PAGE_IN", type, event, FMT_PGIN);
+ else if (event->arg4 == DBG_PAGEINV_FAULT)
+ event_exit("PAGE_IN_FILE", type, event, FMT_PGIN);
+ else if (event->arg4 == DBG_PAGEIND_FAULT)
+ event_exit("PAGE_IN_ANON", type, event, FMT_PGIN);
+ else if (event->arg4 == DBG_CACHE_HIT_FAULT)
+ event_exit("CACHE_HIT", type, event, FMT_CACHEHIT);
+ else if ((ti = event_find(event->threadid, type)))
+ event_delete(ti);
+
+ break;
+
+ default:
+ abort();
+ }
+ }
+ });
- case FILEMGR_PBHMAPID:
- p = "PBHMapID";
- break;
+ if (include_waited_flag || RAW_flag) {
+ ktrace_events_subclass(s, DBG_MACH, DBG_MACH_SCHED, ^(ktrace_event_t event) {
+ int type;
- case FILEMGR_PBHMAPNAME:
- p = "PBHMapName";
- break;
+ type = event->debugid & KDBG_EVENTID_MASK;
- case FILEMGR_PBCLOSE:
- p = "PBClose";
- break;
+ switch (type) {
+ case MACH_idle:
+ case MACH_sched:
+ case MACH_stkhandoff:
+ event_mark_thread_waited(event->threadid);
+ }
+ });
+ }
- case FILEMGR_PBFLUSHFILE:
- p = "PBFlushFile";
- break;
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_FSRW, ^(ktrace_event_t event) {
+ th_info_t ti;
+ int type;
- case FILEMGR_PBGETEOF:
- p = "PBGetEOF";
- break;
+ type = event->debugid & KDBG_EVENTID_MASK;
- case FILEMGR_PBSETEOF:
- p = "PBSetEOF";
- break;
+ switch (type) {
+ case HFS_modify_block_end:
+ /*
+ * the expected path here is as follows:
+ * enter syscall
+ * look up a path, which gets stored in ti->vnode / ti->pathname
+ * modify a metadata block -- we assume the modification has something to do with the path that was looked up
+ * leave syscall
+ * ...
+ * later, someone writes that metadata block; the last path associated with it is attributed
+ */
+ if ((ti = event_find(event->threadid, 0))) {
+ if (ti->newest_pathname)
+ meta_add_name(event->arg2, ti->newest_pathname);
+ }
- case FILEMGR_PBGETFPOS:
- p = "PBGetFPos";
- break;
+ break;
- case FILEMGR_PBREAD:
- p = "PBRead";
- break;
+ case VFS_LOOKUP:
+ if (event->debugid & DBG_FUNC_START) {
+ if ((ti = event_find(event->threadid, 0)) && !ti->vnodeid) {
+ ti->vnodeid = event->arg1;
+ }
+ }
- case FILEMGR_PBWRITE:
- p = "PBWrite";
- break;
+ /* it can be both start and end */
- case FILEMGR_PBGETFCBINFO:
- p = "PBGetFCBInfo";
- break;
+ if (event->debugid & DBG_FUNC_END) {
+ if ((ti = event_find(event->threadid, 0)) && ti->vnodeid) {
+ const char *pathname;
- case FILEMGR_PBSETFINFO:
- p = "PBSetFInfo";
- break;
+ pathname = ktrace_get_path_for_vp(s, ti->vnodeid);
- case FILEMGR_PBALLOCATE:
- p = "PBAllocate";
- break;
+ ti->vnodeid = 0;
- case FILEMGR_PBALLOCCONTIG:
- p = "PBAllocContig";
- break;
+ if (pathname) {
+ if (ti->pathname[0] == '\0') {
+ strncpy(ti->pathname, pathname, MAXPATHLEN);
+ ti->newest_pathname = ti->pathname;
+ } else if (ti->pathname2[0] == '\0') {
+ strncpy(ti->pathname2, pathname, MAXPATHLEN);
+ ti->newest_pathname = ti->pathname2;
+ }
+ }
+ }
+ }
- case FILEMGR_PBSETFPOS:
- p = "PBSetFPos";
- break;
-
- case FILEMGR_PBSETCATINFO:
- p = "PBSetCatInfo";
- break;
-
- case FILEMGR_PBGETVOLPARMS:
- p = "PBGetVolParms";
- break;
-
- case FILEMGR_PBSETVINFO:
- p = "PBSetVInfo";
- break;
-
- case FILEMGR_PBMAKEFSSPEC:
- p = "PBMakeFSSpec";
- break;
-
- case FILEMGR_PBHGETVINFO:
- p = "PBHGetVInfo";
- break;
-
- case FILEMGR_PBCREATEFILEIDREF:
- p = "PBCreateFileIDRef";
- break;
-
- case FILEMGR_PBDELETEFILEIDREF:
- p = "PBDeleteFileIDRef";
- break;
-
- case FILEMGR_PBRESOLVEFILEIDREF:
- p = "PBResolveFileIDRef";
- break;
-
- case FILEMGR_PBFLUSHVOL:
- p = "PBFlushVol";
- break;
-
- case FILEMGR_PBHRENAME:
- p = "PBHRename";
- break;
-
- case FILEMGR_PBCATMOVE:
- p = "PBCatMove";
- break;
+ break;
+ }
- case FILEMGR_PBEXCHANGEFILES:
- p = "PBExchangeFiles";
- break;
+ if (type != Throttled && type != HFS_update)
+ return;
- case FILEMGR_PBHDELETE:
- p = "PBHDelete";
- break;
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ switch (type) {
+ case Throttled:
+ event_exit(" THROTTLED", type, event, FMT_NOTHING);
+ break;
- case FILEMGR_PBDIRCREATE:
- p = "PBDirCreate";
- break;
+ case HFS_update:
+ event_exit(" HFS_update", type, event, FMT_HFS_update);
+ break;
- case FILEMGR_PBCATSEARCH:
- p = "PBCatSearch";
- break;
+ default:
+ abort();
+ }
+ }
+ });
- case FILEMGR_PBHSETFLOCK:
- p = "PBHSetFlock";
- break;
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_DKRW, ^(ktrace_event_t event) {
+ struct diskio *dio;
+ unsigned int type;
- case FILEMGR_PBHRSTFLOCK:
- p = "PBHRstFLock";
- break;
+ type = event->debugid & KDBG_EVENTID_MASK;
- case FILEMGR_PBLOCKRANGE:
- p = "PBLockRange";
- break;
+ if ((type & P_DISKIO_MASK) == P_DISKIO) {
+ diskio_start(type, event->arg1, event->arg2, event->arg3, event->arg4, event);
+ } else if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
+ if ((dio = diskio_complete(event->arg1, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
+ dio->vnodeid = event->arg2;
+ diskio_print(dio);
+ diskio_free(dio);
+ }
+ }
+ });
- case FILEMGR_PBUNLOCKRANGE:
- p = "PBUnlockRange";
- break;
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_IOCTL, ^(ktrace_event_t event) {
+ th_info_t ti;
+ int type;
+ pid_t pid;
- default:
- p = NULL;
- break;
- }
- filemgr_calls[code].fm_name = p;
- }
-}
+ type = event->debugid & KDBG_EVENTID_MASK;
+ switch (type) {
+ case SPEC_unmap_info:
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
+ if (check_filter_mode(pid, NULL, SPEC_unmap_info, 0, 0, "SPEC_unmap_info"))
+ format_print(NULL, " TrimExtent", event, type, FMT_UNMAP_INFO, event->timestamp, event->timestamp, 0, "", NULL);
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
- char *myname = "fs_usage";
- int i;
- char ch;
+ break;
- if (0 != reexec_to_match_kernel()) {
- fprintf(stderr, "Could not re-execute: %d\n", errno);
- exit(1);
- }
- get_screenwidth();
+ case SPEC_ioctl:
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ if (event->arg2 == DKIOCSYNCHRONIZECACHE)
+ event_exit("IOCTL", type, event, FMT_IOCTL_SYNCCACHE);
+ else if (event->arg2 == DKIOCUNMAP)
+ event_exit("IOCTL", type, event, FMT_IOCTL_UNMAP);
+ else if (event->arg2 == DKIOCSYNCHRONIZE && (event->debugid & DBG_FUNC_ALL) == DBG_FUNC_NONE)
+ event_exit("IOCTL", type, event, FMT_IOCTL_SYNC);
+ else if ((ti = event_find(event->threadid, type)))
+ event_delete(ti);
+ }
- /*
- * get our name
- */
- if (argc > 0) {
- if ((myname = rindex(argv[0], '/')) == 0)
- myname = argv[0];
- else
- myname++;
- }
-
- while ((ch = getopt(argc, argv, "ewf:R:S:E:")) != EOF) {
-
- switch(ch) {
-
- case 'e':
- exclude_pids = 1;
- exclude_default_pids = 0;
- break;
-
- case 'w':
- wideflag = 1;
- if ((uint)columns < MAX_WIDE_MODE_COLS)
- columns = MAX_WIDE_MODE_COLS;
- break;
-
- case 'f':
- if (!strcmp(optarg, "network"))
- filter_mode |= NETWORK_FILTER;
- else if (!strcmp(optarg, "filesys"))
- filter_mode |= FILESYS_FILTER;
- else if (!strcmp(optarg, "cachehit"))
- filter_mode &= ~CACHEHIT_FILTER; /* turns on CACHE_HIT */
- else if (!strcmp(optarg, "exec"))
- filter_mode |= EXEC_FILTER;
- else if (!strcmp(optarg, "pathname"))
- filter_mode |= PATHNAME_FILTER;
- break;
-
- case 'R':
- RAW_flag = 1;
- RAW_file = optarg;
- break;
-
- case 'S':
- start_time = atof(optarg);
- break;
-
- case 'E':
- end_time = atof(optarg);
- break;
-
- default:
- exit_usage(myname);
- }
- }
- if (!RAW_flag) {
- if ( geteuid() != 0 ) {
- fprintf(stderr, "'fs_usage' must be run as root...\n");
- exit(1);
+ break;
}
+ });
+
+ if (BC_flag || RAW_flag) {
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_BOOTCACHE, ^(ktrace_event_t event) {
+ struct diskio *dio;
+ unsigned int type;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ switch (type) {
+ case BC_IO_HIT:
+ case BC_IO_HIT_STALLED:
+ case BC_IO_MISS:
+ case BC_IO_MISS_CUT_THROUGH:
+ case BC_PLAYBACK_IO:
+ if ((dio = diskio_find(event->arg1)) != NULL)
+ dio->bc_info = type;
+ }
+ });
}
- argc -= optind;
- argv += optind;
- /*
- * when excluding, fs_usage should be the first in line for pids[]
- *
- * the !exclude_pids && argc == 0 catches the exclude_default_pids
- * case below where exclude_pids is later set and the fs_usage PID
- * needs to make it into pids[]
- */
- if (exclude_pids || (!exclude_pids && argc == 0)) {
- if (num_of_pids < (MAX_PIDS - 1))
- pids[num_of_pids++] = getpid();
- }
+ void (^bsd_sc_proc_cb)(ktrace_event_t event) = ^(ktrace_event_t event) {
+ int type, index;
+ pid_t pid;
- /*
- * If we process any list of pids/cmds, then turn off the defaults
- */
- if (argc > 0)
- exclude_default_pids = 0;
+ type = event->debugid & KDBG_EVENTID_MASK;
- while (argc > 0 && num_of_pids < (MAX_PIDS - 1)) {
- select_pid_mode++;
- argtopid(argv[0]);
- argc--;
- argv++;
- }
- /*
- * Exclude a set of default pids
- */
- if (exclude_default_pids) {
- argtopid("Terminal");
- argtopid("telnetd");
- argtopid("telnet");
- argtopid("sshd");
- argtopid("rlogind");
- argtopid("tcsh");
- argtopid("csh");
- argtopid("sh");
- exclude_pids = 1;
- }
-#if 0
- for (i = 0; i < num_of_pids; i++) {
- if (exclude_pids)
- fprintf(stderr, "exclude pid %d\n", pids[i]);
- else
- fprintf(stderr, "pid %d\n", pids[i]);
- }
-#endif
- if (!RAW_flag) {
- struct sigaction osa;
- int num_cpus;
- size_t len;
-
- /* set up signal handlers */
- signal(SIGINT, leave);
- signal(SIGQUIT, leave);
-
- sigaction(SIGHUP, (struct sigaction *)NULL, &osa);
+ switch (type) {
+ case BSC_exit: /* see below */
+ return;
- if (osa.sa_handler == SIG_DFL)
- signal(SIGHUP, leave);
- signal(SIGTERM, leave);
- /*
- * grab the number of cpus
- */
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- mib[2] = 0;
- len = sizeof(num_cpus);
+ case proc_exit:
+ event->arg1 = event->arg2 >> 8;
+ type = BSC_exit;
- sysctl(mib, 2, &num_cpus, &len, NULL, 0);
- num_events = EVENT_BASE * num_cpus;
- }
- signal(SIGWINCH, sigwinch);
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
+ fd_clear_pid(pid);
- if ((my_buffer = malloc(num_events * sizeof(kd_buf))) == (char *)0)
- quit("can't allocate memory for tracing info\n");
+ break;
- if (ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_i386.map", &framework32, "/var/db/dyld/dyld_shared_cache_i386")) {
- ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_x86_64.map", &framework64, "/var/db/dyld/dyld_shared_cache_x86_64");
- } else {
- ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_ppc.map", &framework32, "/var/db/dyld/dyld_shared_cache_ppc");
- ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_ppc64.map", &framework64, "/var/db/dyld/dyld_shared_cache_ppc64");
- }
- SortFrameworkAddresses();
+ case BSC_mmap:
+ if (event->arg4 & MAP_ANON)
+ return;
- cache_disk_names();
+ break;
+ }
- if (!RAW_flag) {
+ if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
+ return;
- set_remove();
- set_numbufs(num_events);
- set_init();
+ if (!bsd_syscalls[index].sc_name)
+ return;
- if (exclude_pids == 0) {
- for (i = 0; i < num_of_pids; i++)
- set_pidcheck(pids[i], 1);
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
} else {
- for (i = 0; i < num_of_pids; i++)
- set_pidexclude(pids[i], 1);
- }
- if (select_pid_mode && !one_good_pid) {
- /*
- * An attempt to restrict output to a given
- * pid or command has failed. Exit gracefully
- */
- set_remove();
- exit_usage(myname);
+ event_exit(bsd_syscalls[index].sc_name, type, event, bsd_syscalls[index].sc_format);
}
- set_enable(1);
-
- init_arguments_buffer();
- }
- getdivisor();
+ };
+
+ ktrace_events_subclass(s, DBG_BSD, DBG_BSD_EXCP_SC, bsd_sc_proc_cb);
+ ktrace_events_subclass(s, DBG_BSD, DBG_BSD_PROC, bsd_sc_proc_cb);
+
+ 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) {
+ extend_syscall(event->threadid, event->debugid & KDBG_EVENTID_MASK, event);
+ });
+
+ ktrace_events_subclass(s, DBG_CORESTORAGE, DBG_CS_IO, ^(ktrace_event_t event) {
+ // the usual DBG_FUNC_START/END does not work for i/o since it will
+ // return on a different thread, this code uses the P_CS_IO_Done (0x4) bit
+ // instead. the trace command doesn't know how handle either method
+ // (unmatched start/end or 0x4) but works a little better this way.
+
+ struct diskio *dio;
+ int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
+ bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
+
+ switch (cs_type) {
+ case P_CS_ReadChunk:
+ case P_CS_WriteChunk:
+ case P_CS_MetaRead:
+ case P_CS_MetaWrite:
+ if (start) {
+ diskio_start(cs_type, event->arg2, event->arg1, event->arg3, event->arg4, event);
+ } else {
+ if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
+ diskio_print(dio);
+ diskio_free(dio);
+ }
+ }
- init_tables();
+ break;
+ case P_CS_TransformRead:
+ case P_CS_TransformWrite:
+ case P_CS_MigrationRead:
+ case P_CS_MigrationWrite:
+ if (start) {
+ diskio_start(cs_type, event->arg2, CS_DEV, event->arg3, event->arg4, event);
+ } else {
+ if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
+ diskio_print(dio);
+ diskio_free(dio);
+ }
+ }
- /*
- * main loop
- */
- while (1) {
- if (!RAW_flag)
- usleep(1000 * usleep_ms);
+ break;
+ }
+ });
- sample_sc();
+ ktrace_events_subclass(s, DBG_CORESTORAGE, 1 /* DBG_CS_SYNC */, ^(ktrace_event_t event) {
+ int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
+ bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
- last_time = time((long *)0);
- }
+ if (cs_type == P_CS_SYNC_DISK) {
+ if (start) {
+ event_enter(cs_type, event);
+ } else {
+ event_exit(" SyncCacheCS", cs_type, event, FMT_SYNC_DISK_CS);
+ }
+ }
+ });
}
+static void
+extend_syscall_rw(th_info_t ti, ktrace_event_t event)
+{
+ ti->arg1 = event->arg1; /* the fd */
+ ti->arg2 = event->arg2; /* nbytes */
+ ti->arg3 = event->arg3; /* top half offset */
+ ti->arg4 = event->arg4; /* bottom half offset */
+}
+/*
+ * Handle system call extended trace data.
+ * pread and pwrite:
+ * Wipe out the kd args that were collected upon syscall_entry
+ * because it is the extended info that we really want, and it
+ * is all we really need.
+ */
void
-find_proc_names()
+extend_syscall(uint64_t thread, int type, ktrace_event_t event)
{
- size_t bufSize = 0;
- struct kinfo_proc *kp;
+ th_info_t ti;
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_ALL;
- mib[3] = 0;
+ switch (type) {
+ case BSC_mmap_extended:
+ if ((ti = event_find(thread, BSC_mmap)) == NULL) {
+ return;
+ }
- if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0)
- quit("trace facility failure, KERN_PROC_ALL\n");
+ ti->arg8 = ti->arg3; /* save protection */
+ ti->arg1 = event->arg1; /* the fd */
+ ti->arg3 = event->arg2; /* bottom half address */
+ ti->arg5 = event->arg3; /* bottom half size */
+ break;
- if ((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0)
- quit("can't allocate memory for proc buffer\n");
-
- if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0)
- quit("trace facility failure, KERN_PROC_ALL\n");
+ case BSC_mmap_extended2:
+ if ((ti = event_find(thread, BSC_mmap)) == NULL)
+ return;
- kp_nentries = bufSize/ sizeof(struct kinfo_proc);
- kp_buffer = kp;
-}
+ ti->arg2 = event->arg1; /* top half address */
+ ti->arg4 = event->arg2; /* top half size */
+ ti->arg6 = event->arg3; /* top half file offset */
+ ti->arg7 = event->arg4; /* bottom half file offset */
+ break;
+ case BSC_msync_extended:
+ if ((ti = event_find(thread, BSC_msync)) == NULL) {
+ if ((ti = event_find(thread, BSC_msync_nocancel)) == NULL) {
+ return;
+ }
+ }
-void
-set_enable(int val)
-{
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDENABLE; /* protocol */
- mib[3] = val;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
-
- if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDENABLE\n");
-
- if (val)
- trace_enabled = 1;
- else
- trace_enabled = 0;
-}
+ ti->arg4 = event->arg1; /* top half address */
+ ti->arg5 = event->arg2; /* top half size */
+ break;
-void
-set_numbufs(int nbufs)
-{
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDSETBUF;
- mib[3] = nbufs;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
-
- if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETBUF\n");
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDSETUP;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
-
- if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETUP\n");
-}
+ case BSC_pread_extended:
+ if ((ti = event_find(thread, BSC_pread)) == NULL) {
+ if ((ti = event_find(thread, BSC_pread_nocancel)) == NULL) {
+ return;
+ }
+ }
-void
-set_pidcheck(int pid, int on_off)
-{
- kd_regtype kr;
-
- kr.type = KDBG_TYPENONE;
- kr.value1 = pid;
- kr.value2 = on_off;
- needed = sizeof(kd_regtype);
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDPIDTR;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0;
-
- if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
- if (on_off == 1)
- fprintf(stderr, "pid %d does not exist\n", pid);
- } else
- one_good_pid++;
-}
+ extend_syscall_rw(ti, event);
+ break;
-/*
- * on_off == 0 turns off pid exclusion
- * on_off == 1 turns on pid exclusion
- */
-void
-set_pidexclude(int pid, int on_off)
-{
- kd_regtype kr;
-
- one_good_pid++;
-
- kr.type = KDBG_TYPENONE;
- kr.value1 = pid;
- kr.value2 = on_off;
- needed = sizeof(kd_regtype);
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDPIDEX;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0;
-
- if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
- if (on_off == 1)
- fprintf(stderr, "pid %d does not exist\n", pid);
- }
-}
+ case BSC_pwrite_extended:
+ if ((ti = event_find(thread, BSC_pwrite)) == NULL) {
+ if ((ti = event_find(thread, BSC_pwrite_nocancel)) == NULL) {
+ return;
+ }
+ }
-void
-get_bufinfo(kbufinfo_t *val)
-{
- needed = sizeof (*val);
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDGETBUF;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
+ extend_syscall_rw(ti, event);
+ break;
- if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
- quit("trace facility failure, KERN_KDGETBUF\n");
+ case BSC_guarded_pwrite_extended:
+ if ((ti = event_find(thread, BSC_guarded_pwrite_np)) == NULL) {
+ return;
+ }
+ extend_syscall_rw(ti, event);
+ break;
+ }
}
-void
-set_remove()
-{
- errno = 0;
+#pragma mark printing routines
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDREMOVE; /* protocol */
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
+static void
+get_mode_nibble(char *buf, uint64_t smode, uint64_t special, char x_on, char x_off)
+{
+ if (smode & 04)
+ buf[0] = 'r';
- if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
- set_remove_flag = 0;
+ if (smode & 02)
+ buf[1] = 'w';
- if (errno == EBUSY)
- quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
+ if (smode & 01) {
+ if (special)
+ buf[2] = x_on;
else
- quit("trace facility failure, KERN_KDREMOVE\n");
+ buf[2] = 'x';
+ } else {
+ if (special)
+ buf[2] = x_off;
}
}
-void
-set_init()
-{ kd_regtype kr;
-
- kr.type = KDBG_RANGETYPE;
- kr.value1 = 0;
- kr.value2 = -1;
- needed = sizeof(kd_regtype);
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDSETREG;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
-
- if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETREG\n");
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDSETUP;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
-
- if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETUP\n");
+static void
+get_mode_string(uint64_t mode, char *buf)
+{
+ memset(buf, '-', 9);
+ buf[9] = '\0';
+
+ get_mode_nibble(&buf[6], mode, (mode & 01000), 't', 'T');
+ get_mode_nibble(&buf[3], (mode>>3), (mode & 02000), 's', 'S');
+ get_mode_nibble(&buf[0], (mode>>6), (mode & 04000), 's', 'S');
}
-void
-sample_sc()
+static int
+clip_64bit(char *s, uint64_t value)
{
- kd_buf *kd;
- int i, count;
- size_t needed;
- uint32_t my_buffer_size = 0;
+ int clen = 0;
- if (!RAW_flag)
- get_bufinfo(&bufinfo);
+ if ( (value & 0xff00000000000000LL) )
+ clen = printf("%s0x%16.16qx", s, value);
+ else if ( (value & 0x00ff000000000000LL) )
+ clen = printf("%s0x%14.14qx ", s, value);
+ else if ( (value & 0x0000ff0000000000LL) )
+ clen = printf("%s0x%12.12qx ", s, value);
+ else if ( (value & 0x000000ff00000000LL) )
+ clen = printf("%s0x%10.10qx ", s, value);
else
- my_buffer_size = num_events * sizeof(kd_buf);
-
- if (need_new_map) {
- read_command_map();
- need_new_map = 0;
- }
- if (!RAW_flag) {
- needed = bufinfo.nkdbufs * sizeof(kd_buf);
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDREADTR;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
-
- if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDREADTR\n");
- count = needed;
-
- if (count > (num_events / 8)) {
- if (usleep_ms > USLEEP_BEHIND)
- usleep_ms = USLEEP_BEHIND;
- else if (usleep_ms > USLEEP_MIN)
- usleep_ms /= 2;
-
- } else if (count < (num_events / 16)) {
- if (usleep_ms < USLEEP_MAX)
- usleep_ms *= 2;
- }
+ clen = printf("%s0x%8.8qx ", s, value);
- if (bufinfo.flags & KDBG_WRAPPED) {
- fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly: %d\n", count);
+ return clen;
+}
- delete_all_events();
+/*
+ * ret = 1 means print the entry
+ * ret = 0 means don't print the entry
+ */
- need_new_map = 1;
-
- set_enable(0);
- set_enable(1);
- }
- } else {
- int bytes_read;
+/*
+ * meaning of filter flags:
+ * cachehit turn on display of CACHE_HIT events (which are filtered out by default)
+ *
+ * exec show exec/posix_spawn
+ * pathname show events with a pathname and close()
+ * diskio show disk I/Os
+ * filesys show filesystem events
+ * network show network events
+ *
+ * filters may be combined; default is all filters on (except cachehit)
+ */
+bool
+check_filter_mode(pid_t pid, th_info_t ti, uint64_t type, int error, int retval, char *sc_name)
+{
+ bool ret = false;
+ int network_fd_isset = 0;
+ uint64_t fd;
- if ((bytes_read = read(RAW_fd, my_buffer, my_buffer_size)) < sizeof(kd_buf))
- exit(0);
- count = bytes_read / sizeof(kd_buf);
+ /* cachehit is special -- it's not on by default */
+ if (sc_name[0] == 'C' && !strcmp(sc_name, "CACHE_HIT")) {
+ return show_cachehits;
}
- kd = (kd_buf *)my_buffer;
-#if 0
- fprintf(stderr, "READTR returned %d items\n", count);
-#endif
- for (i = 0; i < count; i++) {
- uint32_t debugid;
- uintptr_t thread;
- int type;
- int index;
- uintptr_t *sargptr;
- uint64_t now;
- long long l_usecs;
- int secs;
- long curr_time;
- th_info_t ti;
- struct diskio *dio;
+ if (filter_mode == DEFAULT_DO_NOT_FILTER)
+ return true;
- thread = kd[i].arg5;
- debugid = kd[i].debugid;
- type = kd[i].debugid & DBG_FUNC_MASK;
+ if (filter_mode & DISKIO_FILTER) {
+ if ((type & P_DISKIO_MASK) == P_DISKIO)
+ return true;
- now = kdbg_get_timestamp(&kd[i]);
+ if (type == Throttled)
+ return true;
+ }
- if (i == 0 && !RAW_flag) {
+ if (filter_mode & EXEC_FILTER) {
+ if (type == BSC_execve || type == BSC_posix_spawn)
+ return true;
+ }
- curr_time = time((long *)0);
- /*
- * Compute bias seconds after each trace buffer read.
- * This helps resync timestamps with the system clock
- * in the event of a system sleep.
- */
- if (bias_secs == 0 || curr_time < last_time || curr_time > (last_time + 2)) {
- l_usecs = (long long)(now / divisor);
- secs = l_usecs / 1000000;
- bias_secs = curr_time - secs;
- }
- }
- if (RAW_flag && bias_now == 0.0)
- bias_now = now;
-
- if ((type & P_DISKIO_MASK) == P_DISKIO) {
- insert_diskio(type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4, thread, (double)now);
- continue;
- }
- if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
- if ((dio = complete_diskio(kd[i].arg1, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
- print_diskio(dio);
- free_diskio(dio);
- }
- continue;
- }
+ if (filter_mode & PATHNAME_FILTER) {
+ if (ti && ti->pathname[0])
+ return true;
- if ((type & CLASS_MASK) == P_CS_Class) {
+ if (type == BSC_close || type == BSC_close_nocancel ||
+ type == BSC_guarded_close_np)
+ return true;
+ }
- // the usual DBG_FUNC_START/END does not work for i/o since it will
- // return on a different thread, this code uses the P_CS_IO_Done (0x4) bit
- // instead. the trace command doesn't know how handle either method
- // (unmatched start/end or 0x4) but works a little better this way.
+ if (!ti) {
+ if (filter_mode & FILESYS_FILTER)
+ return true;
- int cs_type = type & P_CS_Type_Mask; // strip out the done bit
- bool start = (type & P_CS_IO_Done) != P_CS_IO_Done;
+ return 0;
+ }
- switch (cs_type) {
-
- case P_CS_ReadChunk:
- case P_CS_WriteChunk:
- case P_CS_MetaRead:
- case P_CS_MetaWrite:
- if (start) {
- insert_diskio(cs_type, kd[i].arg2, kd[i].arg1, kd[i].arg3, kd[i].arg4, thread, (double)now);
+ switch (type) {
+ case BSC_close:
+ case BSC_close_nocancel:
+ case BSC_guarded_close_np:
+ fd = ti->arg1;
+ network_fd_isset = fd_is_network(pid, fd);
+
+ if (error == 0)
+ fd_set_is_network(pid, fd, false);
+
+ if (network_fd_isset) {
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
} else {
- if ((dio = complete_diskio(kd[i].arg2, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
- print_diskio(dio);
- free_diskio(dio);
- }
+ if (filter_mode & FILESYS_FILTER)
+ ret = true;
}
- continue;
- case P_CS_TransformRead:
- case P_CS_TransformWrite:
- case P_CS_MigrationRead:
- case P_CS_MigrationWrite:
- if (start) {
- insert_diskio(cs_type, kd[i].arg2, CS_DEV, kd[i].arg3, kd[i].arg4, thread, (double)now);
- } else {
- if ((dio = complete_diskio(kd[i].arg2, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
- print_diskio(dio);
- free_diskio(dio);
- }
- }
- continue;
-
- case P_CS_SYNC_DISK:
- if (start) {
- enter_event(thread, cs_type, &kd[i], NULL, (double)now);
- } else {
- exit_event(" SyncCacheCS", thread, cs_type, kd[i].arg1, 0, 0, 0, FMT_SYNC_DISK_CS, (double)now);
+ break;
+
+ case BSC_read:
+ case BSC_write:
+ case BSC_read_nocancel:
+ case BSC_write_nocancel:
+ /*
+ * we don't care about error in these cases
+ */
+ fd = ti->arg1;
+
+ if (fd_is_network(pid, fd)) {
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
+ } else if (filter_mode & FILESYS_FILTER) {
+ ret = true;
}
- continue;
- }
-
- continue; // ignore other cs timestamps
- }
-
- switch (type) {
-
- case TRACE_DATA_NEWTHREAD:
- if (kd[i].arg1) {
- if ((ti = add_event(thread, TRACE_DATA_NEWTHREAD)) == NULL)
- continue;
- ti->child_thread = kd[i].arg1;
- ti->pid = kd[i].arg2;
- }
- continue;
-
- case TRACE_STRING_NEWTHREAD:
- if ((ti = find_event(thread, TRACE_DATA_NEWTHREAD)) == (struct th_info *)0)
- continue;
-
- create_map_entry(ti->child_thread, ti->pid, (char *)&kd[i].arg1);
-
- delete_event(ti);
- continue;
-
- case TRACE_DATA_EXEC:
- if ((ti = add_event(thread, TRACE_DATA_EXEC)) == NULL)
- continue;
-
- ti->pid = kd[i].arg1;
- continue;
-
- case TRACE_STRING_EXEC:
- if ((ti = find_event(thread, BSC_execve))) {
- if (ti->pathname[0])
- exit_event("execve", thread, BSC_execve, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
-
- } else if ((ti = find_event(thread, BSC_posix_spawn))) {
- if (ti->pathname[0])
- exit_event("posix_spawn", thread, BSC_posix_spawn, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
- }
- if ((ti = find_event(thread, TRACE_DATA_EXEC)) == (struct th_info *)0)
- continue;
-
- create_map_entry(thread, ti->pid, (char *)&kd[i].arg1);
-
- delete_event(ti);
- continue;
-
- case BSC_thread_terminate:
- delete_map_entry(thread);
- continue;
-
- case BSC_exit:
- continue;
-
- case proc_exit:
- kd[i].arg1 = kd[i].arg2 >> 8;
- type = BSC_exit;
- break;
-
- case BSC_mmap:
- if (kd[i].arg4 & MAP_ANON)
- continue;
- break;
-
- case MACH_idle:
- case MACH_sched:
- case MACH_stkhandoff:
- mark_thread_waited(thread);
- continue;
-
- case VFS_LOOKUP:
- if ((ti = find_event(thread, 0)) == (struct th_info *)0)
- continue;
-
- if (debugid & DBG_FUNC_START) {
- if (ti->pathname2[0])
- continue;
- if (ti->pathname[0] == 0)
- sargptr = ti->pathname;
- else
- sargptr = ti->pathname2;
- *sargptr++ = kd[i].arg2;
- *sargptr++ = kd[i].arg3;
- *sargptr++ = kd[i].arg4;
- /*
- * NULL terminate the 'string'
- */
- *sargptr = 0;
-
- ti->pathptr = sargptr;
- } else {
- sargptr = ti->pathptr;
-
- /*
- * We don't want to overrun our pathname buffer if the
- * kernel sends us more VFS_LOOKUP entries than we can
- * handle and we only handle 2 pathname lookups for
- * a given system call
- */
- if (sargptr == 0)
- continue;
- if (ti->pathname2[0]) {
- if ((uintptr_t)sargptr >= (uintptr_t)&ti->pathname2[NUMPARMS])
- continue;
- } else {
- if ((uintptr_t)sargptr >= (uintptr_t)&ti->pathname[NUMPARMS])
- continue;
- }
- *sargptr++ = kd[i].arg1;
- *sargptr++ = kd[i].arg2;
- *sargptr++ = kd[i].arg3;
- *sargptr++ = kd[i].arg4;
- /*
- * NULL terminate the 'string'
- */
- *sargptr = 0;
-
- if (debugid & DBG_FUNC_END) {
- if (ti->pathname2[0])
- ti->pathptr = 0;
- else
- ti->pathptr = ti->pathname2;
- } else
- ti->pathptr = sargptr;
- }
- continue;
- }
- if (debugid & DBG_FUNC_START) {
- char * p;
+ break;
- if ((type & CLASS_MASK) == FILEMGR_BASE) {
+ case BSC_accept:
+ case BSC_accept_nocancel:
+ case BSC_socket:
+ fd = retval;
- index = filemgr_index(type);
+ if (error == 0)
+ fd_set_is_network(pid, fd, true);
- if (index >= MAX_FILEMGR)
- continue;
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
- if ((p = filemgr_calls[index].fm_name) == NULL)
- continue;
- } else
- p = NULL;
+ break;
- enter_event(thread, type, &kd[i], p, (double)now);
- continue;
- }
+ case BSC_recvfrom:
+ case BSC_sendto:
+ case BSC_recvmsg:
+ case BSC_sendmsg:
+ case BSC_connect:
+ case BSC_bind:
+ case BSC_listen:
+ case BSC_sendto_nocancel:
+ case BSC_recvfrom_nocancel:
+ case BSC_recvmsg_nocancel:
+ case BSC_sendmsg_nocancel:
+ case BSC_connect_nocancel:
+ fd = ti->arg1;
+
+ if (error == 0)
+ fd_set_is_network(pid, fd, true);
+
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
- switch (type) {
+ break;
- case Throttled:
- exit_event(" THROTTLED", thread, type, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
- continue;
+ case BSC_select:
+ case BSC_select_nocancel:
+ case BSC_socketpair:
+ /*
+ * Cannot determine info about file descriptors
+ */
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
- case SPEC_unmap_info:
- if (check_filter_mode(NULL, SPEC_unmap_info, 0, 0, "SPEC_unmap_info"))
- format_print(NULL, " TrimExtent", thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, 0, FMT_UNMAP_INFO, now, now, 0, "", NULL);
- continue;
+ break;
- case SPEC_ioctl:
- if (kd[i].arg2 == DKIOCSYNCHRONIZECACHE)
- exit_event("IOCTL", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_IOCTL_SYNC, (double)now);
- else if (kd[i].arg2 == DKIOCUNMAP)
- exit_event("IOCTL", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_IOCTL_UNMAP, (double)now);
- else {
- if ((ti = find_event(thread, type)))
- delete_event(ti);
- }
- continue;
+ case BSC_dup:
+ case BSC_dup2:
+ /*
+ * We track these cases for fd state only
+ */
+ fd = ti->arg1;
- case MACH_pageout:
- if (kd[i].arg2)
- exit_event("PAGE_OUT_ANON", thread, type, 0, kd[i].arg1, 0, 0, FMT_PGOUT, (double)now);
- else
- exit_event("PAGE_OUT_FILE", thread, type, 0, kd[i].arg1, 0, 0, FMT_PGOUT, (double)now);
- continue;
+ if (error == 0 && fd_is_network(pid, fd)) {
+ /*
+ * then we are duping a socket descriptor
+ */
+ fd = retval; /* the new fd */
+ fd_set_is_network(pid, fd, true);
+ }
- case MACH_vmfault:
- if (kd[i].arg4 == DBG_PAGEIN_FAULT)
- exit_event("PAGE_IN", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
- else if (kd[i].arg4 == DBG_PAGEINV_FAULT)
- exit_event("PAGE_IN_FILE", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
- else if (kd[i].arg4 == DBG_PAGEIND_FAULT)
- exit_event("PAGE_IN_ANON", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
- else if (kd[i].arg4 == DBG_CACHE_HIT_FAULT)
- exit_event("CACHE_HIT", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_CACHEHIT, (double)now);
- else {
- if ((ti = find_event(thread, type)))
- delete_event(ti);
- }
- continue;
+ break;
- case MSC_map_fd:
- exit_event("map_fd", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_FD, (double)now);
- continue;
-
- case BSC_mmap_extended:
- case BSC_mmap_extended2:
- case BSC_msync_extended:
- case BSC_pread_extended:
- case BSC_pwrite_extended:
- extend_syscall(thread, type, &kd[i]);
- continue;
- }
+ default:
+ if (filter_mode & FILESYS_FILTER)
+ ret = true;
- if ((type & CSC_MASK) == BSC_BASE) {
+ break;
+ }
- if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
- continue;
+ return ret;
+}
- if (bsd_syscalls[index].sc_name) {
- exit_event(bsd_syscalls[index].sc_name, thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4,
- bsd_syscalls[index].sc_format, (double)now);
+int
+print_open(ktrace_event_t event, uint64_t flags)
+{
+ char mode[] = {
+ '_',
+ '_',
+ (flags & O_CREAT) ? 'C' : '_',
+ (flags & O_APPEND) ? 'A' : '_',
+ (flags & O_TRUNC) ? 'T' : '_',
+ (flags & O_EXCL) ? 'E' : '_',
+ (flags & O_NONBLOCK) ? 'N' : '_',
+ (flags & O_SHLOCK) ? 'l' : (flags & O_EXLOCK) ? 'L' : '_',
+ (flags & O_NOFOLLOW) ? 'F' : '_',
+ (flags & O_SYMLINK) ? 'S' : '_',
+ (flags & O_EVTONLY) ? 'V' : '_',
+ (flags & O_CLOEXEC) ? 'X' : '_',
+ '\0',
+ };
+
+ if (flags & O_RDWR) {
+ mode[0] = 'R';
+ mode[1] = 'W';
+ } else if (flags & O_WRONLY) {
+ mode[1] = 'W';
+ } else {
+ mode[0] = 'R';
+ }
- if (type == BSC_exit)
- delete_map_entry(thread);
- }
- } else if ((type & CLASS_MASK) == FILEMGR_BASE) {
-
- if ((index = filemgr_index(type)) >= MAX_FILEMGR)
- continue;
-
- if (filemgr_calls[index].fm_name) {
- exit_event(filemgr_calls[index].fm_name, thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4,
- FMT_DEFAULT, (double)now);
- }
- }
+ if (event->arg1) {
+ return printf(" [%3d] (%s) ", (int)event->arg1, mode);
+ } else {
+ return printf(" F=%-3d (%s) ", (int)event->arg2, mode);
}
- fflush(0);
}
-
+/*
+ * called from:
+ *
+ * exit_event() (syscalls etc.)
+ * print_diskio() (disk I/Os)
+ * block callback for TrimExtent
+ */
void
-enter_event_now(uintptr_t thread, int type, kd_buf *kd, char *name, double now)
+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)
{
- th_info_t ti;
- threadmap_t tme;
- int secs;
- int usecs;
- long long l_usecs;
- long curr_time;
+ uint64_t secs, usecs;
+ int nopadding = 0;
+ static time_t last_walltime_secs = -1;
+ const char *command_name;
+ pid_t pid;
+ int len = 0;
int clen = 0;
- int tsclen = 0;
- int nmclen = 0;
- int argsclen = 0;
- char buf[MAXWIDTH];
-
- if ((ti = add_event(thread, type)) == NULL)
- return;
+ size_t tlen = 0;
+ uint64_t class;
+ uint64_t user_addr;
+ uint64_t user_size;
+ char *framework_name;
+ char *framework_type;
+ char *p1;
+ char *p2;
+ char buf[2 * PATH_MAX + 64];
+ char cs_diskname[32];
+ uint64_t threadid;
+ struct timeval now_walltime;
- ti->stime = now;
- ti->arg1 = kd->arg1;
- ti->arg2 = kd->arg2;
- ti->arg3 = kd->arg3;
- ti->arg4 = kd->arg4;
-
- if ((type & CLASS_MASK) == FILEMGR_BASE &&
- (!RAW_flag || (now >= start_time && now <= end_time))) {
-
- filemgr_in_progress++;
- ti->in_filemgr = 1;
-
- if (RAW_flag) {
- l_usecs = (long long)((now - bias_now) / divisor);
- l_usecs += (sample_TOD_secs * 1000000) + sample_TOD_usecs;
- } else
- l_usecs = (long long)(now / divisor);
- secs = l_usecs / 1000000;
- curr_time = bias_secs + secs;
-
- sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
- tsclen = strlen(buf);
-
- if (columns > MAXCOLS || wideflag) {
- usecs = l_usecs - (long long)((long long)secs * 1000000);
- sprintf(&buf[tsclen], ".%06ld", (long)usecs);
- tsclen = strlen(buf);
- }
+ static char timestamp[32];
+ static size_t timestamp_len = 0;
- /*
- * Print timestamp column
- */
- printf("%s", buf);
+ if (!mach_time_of_first_event)
+ mach_time_of_first_event = now;
- tme = find_map_entry(thread);
- if (tme) {
- sprintf(buf, " %-25.25s ", name);
- nmclen = strlen(buf);
- printf("%s", buf);
+ if (format == FMT_DISKIO || format == FMT_DISKIO_CS) {
+ os_assert(dio);
+ } else {
+ os_assert(event);
- sprintf(buf, "(%d, 0x%lx, 0x%lx, 0x%lx)", (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
- argsclen = strlen(buf);
-
- /*
- * Calculate white space out to command
- */
- if (columns > MAXCOLS || wideflag) {
- clen = columns - (tsclen + nmclen + argsclen + 20 + 11);
- } else
- clen = columns - (tsclen + nmclen + argsclen + 12);
-
- if (clen > 0) {
- printf("%s", buf); /* print the kdargs */
- memset(buf, ' ', clen);
- buf[clen] = '\0';
- printf("%s", buf);
- }
- else if ((argsclen + clen) > 0) {
- /*
- * no room so wipe out the kdargs
- */
- memset(buf, ' ', (argsclen + clen));
- buf[argsclen + clen] = '\0';
- printf("%s", buf);
- }
- if (columns > MAXCOLS || wideflag)
- printf("%s.%d\n", tme->tm_command, (int)thread);
- else
- printf("%-12.12s\n", tme->tm_command);
- } else
- printf(" %-24.24s (%5d, %#lx, 0x%lx, 0x%lx)\n", name, (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
+ if (format != FMT_UNMAP_INFO)
+ os_assert(ti);
}
-}
-
-void
-enter_event(uintptr_t thread, int type, kd_buf *kd, char *name, double now)
-{
- int index;
-
- if (type == MACH_pageout || type == MACH_vmfault || type == MSC_map_fd || type == SPEC_ioctl || type == Throttled || type == P_CS_SYNC_DISK) {
- enter_event_now(thread, type, kd, name, now);
+ /* <rdar://problem/19852325> Filter out WindowServer/xcpm ioctls in fs_usage */
+ if (type == BSC_ioctl && ti->arg2 == 0xffffffffc030581dUL)
return;
- }
- if ((type & CSC_MASK) == BSC_BASE) {
- if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
- return;
+ /* honor -S and -E */
+ if (RAW_flag) {
+ uint64_t relative_time_ns;
- if (bsd_syscalls[index].sc_name)
- enter_event_now(thread, type, kd, name, now);
- return;
- }
- if ((type & CLASS_MASK) == FILEMGR_BASE) {
+ relative_time_ns = mach_to_nano(now - mach_time_of_first_event);
- if ((index = filemgr_index(type)) >= MAX_FILEMGR)
+ if (relative_time_ns < start_time_ns || relative_time_ns > end_time_ns)
return;
-
- if (filemgr_calls[index].fm_name)
- enter_event_now(thread, type, kd, name, now);
}
-}
-/*
- * Handle system call extended trace data.
- * pread and pwrite:
- * Wipe out the kd args that were collected upon syscall_entry
- * because it is the extended info that we really want, and it
- * is all we really need.
-*/
+ class = KDBG_EXTRACT_CLASS(type);
-void
-extend_syscall(uintptr_t thread, int type, kd_buf *kd)
-{
- th_info_t ti;
-
- switch (type) {
- case BSC_mmap_extended:
- if ((ti = find_event(thread, BSC_mmap)) == (struct th_info *)0)
- return;
- ti->arg8 = ti->arg3; /* save protection */
- ti->arg1 = kd->arg1; /* the fd */
- ti->arg3 = kd->arg2; /* bottom half address */
- ti->arg5 = kd->arg3; /* bottom half size */
- break;
- case BSC_mmap_extended2:
- if ((ti = find_event(thread, BSC_mmap)) == (struct th_info *)0)
- return;
- ti->arg2 = kd->arg1; /* top half address */
- ti->arg4 = kd->arg2; /* top half size */
- ti->arg6 = kd->arg3; /* top half file offset */
- ti->arg7 = kd->arg4; /* bottom half file offset */
- break;
- case BSC_msync_extended:
- if ((ti = find_event(thread, BSC_msync)) == (struct th_info *)0) {
- if ((ti = find_event(thread, BSC_msync_nocancel)) == (struct th_info *)0)
- return;
- }
- ti->arg4 = kd->arg1; /* top half address */
- ti->arg5 = kd->arg2; /* top half size */
- break;
- case BSC_pread_extended:
- if ((ti = find_event(thread, BSC_pread)) == (struct th_info *)0) {
- if ((ti = find_event(thread, BSC_pread_nocancel)) == (struct th_info *)0)
- return;
- }
- ti->arg1 = kd->arg1; /* the fd */
- ti->arg2 = kd->arg2; /* nbytes */
- ti->arg3 = kd->arg3; /* top half offset */
- ti->arg4 = kd->arg4; /* bottom half offset */
- break;
- case BSC_pwrite_extended:
- if ((ti = find_event(thread, BSC_pwrite)) == (struct th_info *)0) {
- if ((ti = find_event(thread, BSC_pwrite_nocancel)) == (struct th_info *)0)
- return;
- }
- ti->arg1 = kd->arg1; /* the fd */
- ti->arg2 = kd->arg2; /* nbytes */
- ti->arg3 = kd->arg3; /* top half offset */
- ti->arg4 = kd->arg4; /* bottom half offset */
- break;
- default:
- return;
- }
-}
+ if (dio) {
+ command_name = dio->issuing_command;
+ threadid = dio->issuing_thread;
+ pid = dio->issuing_pid;
+ now_walltime = dio->completed_walltime;
+ } else {
+ if (ti && ti->command[0] != '\0') {
+ command_name = ti->command;
+ threadid = ti->thread;
+ pid = ti->pid;
+ } else {
+ command_name = ktrace_get_execname_for_thread(s, event->threadid);
+ threadid = event->threadid;
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
+ }
+ now_walltime = event->walltime;
+ }
-void
-exit_event(char *sc_name, uintptr_t thread, int type, int arg1, int arg2, int arg3, int arg4,
- int format, double now)
-{
- th_info_t ti;
-
- if ((ti = find_event(thread, type)) == (struct th_info *)0)
- return;
+ if (!want_kernel_task && pid == 0)
+ return;
- if (check_filter_mode(ti, type, arg1, arg2, sc_name))
- format_print(ti, sc_name, thread, type, arg1, arg2, arg3, arg4, format, now, ti->stime, ti->waited, (char *)ti->pathname, NULL);
+ if (!command_name)
+ command_name = "";
- if ((type & CLASS_MASK) == FILEMGR_BASE) {
- ti->in_filemgr = 0;
+ os_assert(now_walltime.tv_sec || now_walltime.tv_usec);
- if (filemgr_in_progress > 0)
- filemgr_in_progress--;
+ /* try and reuse the timestamp string */
+ if (last_walltime_secs != now_walltime.tv_sec) {
+ timestamp_len = strftime(timestamp, sizeof (timestamp), "%H:%M:%S", localtime(&now_walltime.tv_sec));
+ last_walltime_secs = now_walltime.tv_sec;
}
- delete_event(ti);
-}
+ if (columns > MAXCOLS || wideflag) {
+ tlen = timestamp_len;
+ nopadding = 0;
-void
-get_mode_nibble(char * buf, int smode, int special, char x_on, char x_off)
-{
- if (smode & 04)
- buf[0] = 'r';
- if (smode & 02)
- buf[1] = 'w';
- if (smode & 01) {
- if (special)
- buf[2] = x_on;
- else
- buf[2] = 'x';
+ sprintf(×tamp[tlen], ".%06d", now_walltime.tv_usec);
+ tlen += 7;
+
+ timestamp[tlen] = '\0';
} else {
- if (special)
- buf[2] = x_off;
+ nopadding = 1;
}
-}
+ clen = printf("%s %-17.17s", timestamp, sc_name);
-void
-get_mode_string(int mode, char *buf)
-{
- memset(buf, '-', 9);
- buf[9] = '\0';
+ framework_name = NULL;
- get_mode_nibble(&buf[6], mode, (mode & 01000), 't', 'T');
- get_mode_nibble(&buf[3], (mode>>3), (mode & 02000), 's', 'S');
- get_mode_nibble(&buf[0], (mode>>6), (mode & 04000), 's', 'S');
-}
+ if (columns > MAXCOLS || wideflag) {
+ off_t offset_reassembled = 0LL;
+ switch (format) {
+ case FMT_NOTHING:
+ clen += printf(" ");
+ break;
-int clip_64bit(char *s, uint64_t value)
-{
- int clen = 0;
+ case FMT_AT:
+ case FMT_RENAMEAT:
+ case FMT_DEFAULT:
+ /*
+ * pathname based system calls or
+ * calls with no fd or pathname (i.e. sync)
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] ", (int)event->arg1);
+ else
+ clen += printf(" ");
- if ( (value & 0xff00000000000000LL) )
- clen = printf("%s0x%16.16qx", s, value);
- else if ( (value & 0x00ff000000000000LL) )
- clen = printf("%s0x%14.14qx ", s, value);
- else if ( (value & 0x0000ff0000000000LL) )
- clen = printf("%s0x%12.12qx ", s, value);
- else if ( (value & 0x000000ff00000000LL) )
- clen = printf("%s0x%10.10qx ", s, value);
- else
- clen = printf("%s0x%8.8qx ", s, value);
-
- return (clen);
-}
+ break;
+ case FMT_FD:
+ /*
+ * fd based system call... no I/O
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
-void
-format_print(struct th_info *ti, char *sc_name, uintptr_t thread, int type, int arg1, int arg2, int arg3, int arg4,
- int format, double now, double stime, int waited, char *pathname, struct diskio *dio)
-{
- int secs;
- int usecs;
- int nopadding = 0;
- long long l_usecs;
- long curr_time;
- char *command_name;
- int in_filemgr = 0;
- int len = 0;
- int clen = 0;
- int tlen = 0;
- int class;
- uint64_t user_addr;
- uint64_t user_size;
- char *framework_name;
- char *framework_type;
- char *p1;
- char *p2;
- char buf[MAXWIDTH];
- char cs_diskname[32];
- command_name = "";
- static char timestamp[32];
- static int last_timestamp = -1;
- static int timestamp_len = 0;
+ break;
- if (RAW_flag) {
- l_usecs = (long long)((now - bias_now) / divisor);
+ case FMT_FD_2:
+ /*
+ * accept, dup, dup2
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d F=%-3d", (int)ti->arg1, (int)event->arg2);
+
+ break;
+
+ case FMT_FD_IO:
+ /*
+ * system calls with fd's that return an I/O completion count
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d B=0x%-6" PRIx64, (int)ti->arg1, (uint64_t)event->arg2);
+
+ break;
+
+ case FMT_PGIN:
+ /*
+ * pagein
+ */
+ user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
+
+ lookup_name(user_addr, &framework_type, &framework_name);
+ clen += clip_64bit(" A=", user_addr);
+ break;
+
+ case FMT_CACHEHIT:
+ /*
+ * cache hit
+ */
+ user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
+
+ lookup_name(user_addr, &framework_type, &framework_name);
+ clen += clip_64bit(" A=", user_addr);
+ break;
- if ((double)l_usecs < start_time || (double)l_usecs > end_time)
- return;
+ case FMT_PGOUT:
+ /*
+ * pageout
+ */
+ clen += printf(" B=0x%-8" PRIx64, (uint64_t)event->arg1);
+ break;
- l_usecs += (sample_TOD_secs * 1000000) + sample_TOD_usecs;
- }
- else
- l_usecs = (long long)(now / divisor);
- secs = l_usecs / 1000000;
- curr_time = bias_secs + secs;
+ case FMT_HFS_update:
+ {
+ static const struct {
+ int flag;
+ char ch;
+ } hfsflags[] = {
+ { DBG_HFS_UPDATE_SKIPPED, 'S' },
+ { DBG_HFS_UPDATE_FORCE, 'F' },
+ { DBG_HFS_UPDATE_MODIFIED, 'M' },
+ { DBG_HFS_UPDATE_MINOR, 'N' },
+ { DBG_HFS_UPDATE_DATEADDED, 'd' },
+ { DBG_HFS_UPDATE_CHGTIME, 'c' },
+ { DBG_HFS_UPDATE_ACCTIME, 'a' },
+ { DBG_HFS_UPDATE_MODTIME, 'm' },
+ };
+ size_t i;
+ int flagcount;
+ char *sbuf;
+ int sflag = (int)event->arg2;
+
+ flagcount = sizeof (hfsflags) / sizeof (*hfsflags);
+ sbuf = malloc(flagcount + 1);
+
+ for (i = 0; i < flagcount; i++) {
+ if (sflag & hfsflags[i].flag) {
+ sbuf[i] = hfsflags[i].ch;
+ } else {
+ sbuf[i] = '_';
+ }
+ }
- class = type >> 24;
+ sbuf[flagcount] = '\0';
- if (dio)
- command_name = dio->issuing_command;
- else {
- threadmap_t tme;
+ clen += printf(" %*s(%s) ", 17 - flagcount, "", sbuf);
- if ((tme = find_map_entry(thread)))
- command_name = tme->tm_command;
- }
- if (last_timestamp != curr_time) {
- timestamp_len = sprintf(timestamp, "%-8.8s", &(ctime(&curr_time)[11]));
- last_timestamp = curr_time;
- }
- if (columns > MAXCOLS || wideflag) {
- int usec;
+ free(sbuf);
- tlen = timestamp_len;
- nopadding = 0;
- usec = (l_usecs - (long long)((long long)secs * 1000000));
+ pathname = ktrace_get_path_for_vp(s, event->arg1);
- sprintf(×tamp[tlen], ".%06ld", (long)usec);
- tlen += 7;
+ if (!pathname)
+ pathname = "";
- timestamp[tlen] = '\0';
+ nopadding = 1;
- if (filemgr_in_progress) {
- if (class != FILEMGR_CLASS) {
- if (find_event(thread, -1))
- in_filemgr = 1;
+ break;
}
- }
- } else
- nopadding = 1;
- if ((class == FILEMGR_CLASS) && (columns > MAXCOLS || wideflag))
- clen = printf("%s %-20.20s", timestamp, sc_name);
- else if (in_filemgr)
- clen = printf("%s %-15.15s", timestamp, sc_name);
- else
- clen = printf("%s %-17.17s", timestamp, sc_name);
-
+ case FMT_DISKIO:
+ /*
+ * physical disk I/O
+ */
+ if (dio->io_errno) {
+ clen += printf(" D=0x%8.8" PRIx64 " [%3d]", dio->blkno, (int)dio->io_errno);
+ } else {
+ if (BC_flag)
+ 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));
+ else
+ clen += printf(" D=0x%8.8" PRIx64 " B=0x%-6" PRIx64 " /dev/%s ", dio->blkno, dio->iosize, find_disk_name(dio->dev));
+
+ if (dio->is_meta) {
+ if (!(type & P_DISKIO_READ)) {
+ pathname = meta_find_name(dio->blkno);
+ }
+ } else {
+ pathname = ktrace_get_path_for_vp(s, dio->vnodeid);
+
+ if (!pathname)
+ pathname = "";
+ }
+
+ nopadding = 1;
+ }
- framework_name = NULL;
+ break;
- if (columns > MAXCOLS || wideflag) {
+ case FMT_DISKIO_CS:
+ /*
+ * physical disk I/O
+ */
+ if (dio->io_errno)
+ clen += printf(" D=0x%8.8" PRIx64 " [%3" PRIu64 "]", dio->blkno, dio->io_errno);
+ else
+ 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));
- off_t offset_reassembled = 0LL;
-
- switch (format) {
+ break;
- case FMT_DEFAULT:
- /*
- * pathname based system calls or
- * calls with no fd or pathname (i.e. sync)
- */
- if (arg1)
- clen += printf(" [%3d] ", arg1);
- else
- clen += printf(" ");
- break;
+ case FMT_SYNC_DISK_CS:
+ /*
+ * physical disk sync cache
+ */
+ clen += printf(" /dev/%s", generate_cs_disk_name(event->arg1, cs_diskname));
- case FMT_FD:
- /*
- * fd based system call... no I/O
- */
- if (arg1)
- clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
- else
- clen += printf(" F=%-3d", ti->arg1);
- break;
+ break;
- case FMT_FD_2:
- /*
- * accept, dup, dup2
- */
- if (arg1)
- clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
- else
- clen += printf(" F=%-3d F=%-3d", ti->arg1, arg2);
- break;
+ case FMT_MSYNC:
+ {
+ /*
+ * msync
+ */
+ int mlen = 0;
- case FMT_FD_IO:
- /*
- * system calls with fd's that return an I/O completion count
- */
- if (arg1)
- clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
- else
- clen += printf(" F=%-3d B=0x%-6x", ti->arg1, arg2);
- break;
+ buf[0] = '\0';
- case FMT_PGIN:
- /*
- * pagein
- */
- user_addr = ((uint64_t)arg2 << 32) | (uint32_t)arg3;
+ if (ti->arg3 & MS_ASYNC)
+ mlen += sprintf(&buf[mlen], "MS_ASYNC | ");
+ else
+ mlen += sprintf(&buf[mlen], "MS_SYNC | ");
- lookup_name(user_addr, &framework_type, &framework_name);
- clen += clip_64bit(" A=", user_addr);
- break;
+ if (ti->arg3 & MS_INVALIDATE)
+ mlen += sprintf(&buf[mlen], "MS_INVALIDATE | ");
+ if (ti->arg3 & MS_KILLPAGES)
+ mlen += sprintf(&buf[mlen], "MS_KILLPAGES | ");
+ if (ti->arg3 & MS_DEACTIVATE)
+ mlen += sprintf(&buf[mlen], "MS_DEACTIVATE | ");
- case FMT_CACHEHIT:
- /*
- * cache hit
- */
- user_addr = ((uint64_t)arg2 << 32) | (uint32_t)arg3;
+ if (ti->arg3 & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE | MS_KILLPAGES | MS_DEACTIVATE))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
- lookup_name(user_addr, &framework_type, &framework_name);
- clen += clip_64bit(" A=", user_addr);
- break;
+ if (mlen)
+ buf[mlen - 3] = '\0';
- case FMT_PGOUT:
- /*
- * pageout
- */
- clen += printf(" B=0x%-8x", arg2);
- break;
+ if (event->arg1)
+ clen += printf(" [%3d]", (int)event->arg1);
- case FMT_DISKIO:
- /*
- * physical disk I/O
- */
- if (dio->io_errno)
- clen += printf(" D=0x%8.8x [%3d]", dio->blkno, dio->io_errno);
- else
- clen += printf(" D=0x%8.8x B=0x%-10x /dev/%s", dio->blkno, dio->iosize, find_disk_name(dio->dev));
- break;
+ user_addr = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg1);
+ clen += clip_64bit(" A=", user_addr);
- case FMT_DISKIO_CS:
- /*
- * physical disk I/O
- */
- if (dio->io_errno)
- clen += printf(" D=0x%8.8x [%3d]", dio->blkno, dio->io_errno);
- else
- clen += printf(" D=0x%8.8x B=0x%-10x /dev/%s", dio->blkno, dio->iosize, generate_cs_disk_name(dio->dev, &cs_diskname[0]));
- break;
+ user_size = (((off_t)(unsigned int)(ti->arg5)) << 32) | (unsigned int)(ti->arg2);
- case FMT_SYNC_DISK_CS:
- /*
- * physical disk sync cache
- */
- clen += printf(" /dev/%s", generate_cs_disk_name(arg1, &cs_diskname[0]));
+ clen += printf(" B=0x%-16qx <%s>", user_size, buf);
- break;
+ break;
+ }
- case FMT_MSYNC:
- {
- /*
- * msync
- */
- int mlen = 0;
+ case FMT_FLOCK:
+ {
+ /*
+ * flock
+ */
+ int mlen = 0;
- buf[0] = '\0';
+ buf[0] = '\0';
- if (ti->arg3 & MS_ASYNC)
- mlen += sprintf(&buf[mlen], "MS_ASYNC | ");
- else
- mlen += sprintf(&buf[mlen], "MS_SYNC | ");
+ if (ti->arg2 & LOCK_SH)
+ mlen += sprintf(&buf[mlen], "LOCK_SH | ");
+ if (ti->arg2 & LOCK_EX)
+ mlen += sprintf(&buf[mlen], "LOCK_EX | ");
+ if (ti->arg2 & LOCK_NB)
+ mlen += sprintf(&buf[mlen], "LOCK_NB | ");
+ if (ti->arg2 & LOCK_UN)
+ mlen += sprintf(&buf[mlen], "LOCK_UN | ");
+
+ if (ti->arg2 & ~(LOCK_SH | LOCK_EX | LOCK_NB | LOCK_UN))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen)
+ buf[mlen - 3] = '\0';
+
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d] <%s>", (int)ti->arg1, (int)event->arg1, buf);
+ else
+ clen += printf(" F=%-3d <%s>", (int)ti->arg1, buf);
+
+ break;
+ }
- if (ti->arg3 & MS_INVALIDATE)
- mlen += sprintf(&buf[mlen], "MS_INVALIDATE | ");
- if (ti->arg3 & MS_KILLPAGES)
- mlen += sprintf(&buf[mlen], "MS_KILLPAGES | ");
- if (ti->arg3 & MS_DEACTIVATE)
- mlen += sprintf(&buf[mlen], "MS_DEACTIVATE | ");
+ case FMT_FCNTL:
+ {
+ /*
+ * fcntl
+ */
+ char *p = NULL;
+ int fd = -1;
- if (ti->arg3 & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE | MS_KILLPAGES | MS_DEACTIVATE))
- mlen += sprintf(&buf[mlen], "UNKNOWN | ");
-
- if (mlen)
- buf[mlen - 3] = '\0';
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
- if (arg1)
- clen += printf(" [%3d]", arg1);
+ switch(ti->arg2) {
+ case F_DUPFD:
+ p = "DUPFD";
+ break;
- user_addr = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg1);
- clen += clip_64bit(" A=", user_addr);
+ case F_GETFD:
+ p = "GETFD";
+ break;
- user_size = (((off_t)(unsigned int)(ti->arg5)) << 32) | (unsigned int)(ti->arg2);
+ case F_SETFD:
+ p = "SETFD";
+ break;
- clen += printf(" B=0x%-16qx <%s>", user_size, buf);
+ case F_GETFL:
+ p = "GETFL";
+ break;
- break;
- }
+ case F_SETFL:
+ p = "SETFL";
+ break;
+
+ case F_GETOWN:
+ p = "GETOWN";
+ break;
+
+ case F_SETOWN:
+ p = "SETOWN";
+ break;
+
+ case F_GETLK:
+ p = "GETLK";
+ break;
+
+ case F_SETLK:
+ p = "SETLK";
+ break;
+
+ case F_SETLKW:
+ p = "SETLKW";
+ break;
+
+ case F_SETLKWTIMEOUT:
+ p = "SETLKWTIMEOUT";
+ break;
+
+ case F_GETLKPID:
+ p = "GETLKPID";
+ break;
+
+ case F_OFD_GETLK:
+ p = "OFD_GETLK";
+ break;
+
+ case F_OFD_SETLK:
+ p = "OFD_SETLK";
+ break;
+
+ case F_OFD_SETLKW:
+ p = "OFD_SETLKW";
+ break;
+
+ case F_OFD_SETLKWTIMEOUT:
+ p = "OFD_SETLKWTIMEOUT";
+ break;
+
+ case F_OFD_GETLKPID:
+ p = "OFD_GETLKPID";
+ break;
+
+ case F_PREALLOCATE:
+ p = "PREALLOCATE";
+ break;
+
+ case F_SETSIZE:
+ p = "SETSIZE";
+ break;
+
+ case F_RDADVISE:
+ p = "RDADVISE";
+ break;
+
+ case F_GETPATH:
+ p = "GETPATH";
+ break;
+
+ case F_FULLFSYNC:
+ p = "FULLFSYNC";
+ break;
+
+ case F_PATHPKG_CHECK:
+ p = "PATHPKG_CHECK";
+ break;
+
+ case F_OPENFROM:
+ p = "OPENFROM";
+
+ if (event->arg1 == 0)
+ fd = (int)event->arg2;
+ break;
- case FMT_FCNTL:
- {
- /*
- * fcntl
- */
- char *p = NULL;
- int fd = -1;
+ case F_UNLINKFROM:
+ p = "UNLINKFROM";
+ break;
- if (arg1)
- clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
- else
- clen += printf(" F=%-3d", ti->arg1);
-
- switch(ti->arg2) {
-
- case F_DUPFD:
- p = "DUPFD";
- break;
-
- case F_GETFD:
- p = "GETFD";
- break;
-
- case F_SETFD:
- p = "SETFD";
- break;
-
- case F_GETFL:
- p = "GETFL";
- break;
-
- case F_SETFL:
- p = "SETFL";
- break;
-
- case F_GETOWN:
- p = "GETOWN";
- break;
-
- case F_SETOWN:
- p = "SETOWN";
- break;
-
- case F_GETLK:
- p = "GETLK";
- break;
-
- case F_SETLK:
- p = "SETLK";
- break;
-
- case F_SETLKW:
- p = "SETLKW";
- break;
-
- case F_PREALLOCATE:
- p = "PREALLOCATE";
- break;
-
- case F_SETSIZE:
- p = "SETSIZE";
- break;
-
- case F_RDADVISE:
- p = "RDADVISE";
- break;
-
- case F_GETPATH:
- p = "GETPATH";
- break;
-
- case F_FULLFSYNC:
- p = "FULLFSYNC";
- break;
-
- case F_PATHPKG_CHECK:
- p = "PATHPKG_CHECK";
- break;
-
- case F_OPENFROM:
- p = "OPENFROM";
-
- if (arg1 == 0)
- fd = arg2;
- break;
-
- case F_UNLINKFROM:
- p = "UNLINKFROM";
- break;
-
- case F_CHECK_OPENEVT:
- p = "CHECK_OPENEVT";
- break;
-
- case F_NOCACHE:
- if (ti->arg3)
- p = "CACHING OFF";
- else
- p = "CACHING ON";
- break;
-
- case F_GLOBAL_NOCACHE:
- if (ti->arg3)
- p = "CACHING OFF (GLOBAL)";
- else
- p = "CACHING ON (GLOBAL)";
- break;
+ case F_CHECK_OPENEVT:
+ p = "CHECK_OPENEVT";
+ break;
+
+ case F_NOCACHE:
+ if (ti->arg3)
+ p = "CACHING OFF";
+ else
+ p = "CACHING ON";
+ break;
+
+ case F_GLOBAL_NOCACHE:
+ if (ti->arg3)
+ p = "CACHING OFF (GLOBAL)";
+ else
+ p = "CACHING ON (GLOBAL)";
+ break;
+
+ }
+ if (p) {
+ if (fd == -1)
+ clen += printf(" <%s>", p);
+ else
+ clen += printf(" <%s> F=%d", p, fd);
+ } else {
+ clen += printf(" <CMD=%d>", (int)ti->arg2);
+ }
+
+ break;
}
- if (p) {
- if (fd == -1)
- clen += printf(" <%s>", p);
+
+ case FMT_IOCTL:
+ {
+ /*
+ * ioctl
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
else
- clen += printf(" <%s> F=%d", p, fd);
- } else
- clen += printf(" <CMD=%d>", ti->arg2);
+ clen += printf(" F=%-3d", (int)ti->arg1);
- break;
- }
+ clen += printf(" <CMD=0x%x>", (int)ti->arg2);
- case FMT_IOCTL:
- {
- /*
- * ioctl
- */
- if (arg1)
- clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
- else
- clen += printf(" F=%-3d", ti->arg1);
+ break;
+ }
- clen += printf(" <CMD=0x%x>", ti->arg2);
+ case FMT_IOCTL_SYNC:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCSYNCHRONIZE> B=%" PRIu64 " /dev/%s", (uint64_t)event->arg3, find_disk_name(event->arg1));
- break;
- }
+ break;
+ }
- case FMT_IOCTL_SYNC:
- {
- /*
- * ioctl
- */
- clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(arg1));
+ case FMT_IOCTL_SYNCCACHE:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(event->arg1));
- break;
- }
+ break;
+ }
- case FMT_IOCTL_UNMAP:
- {
- /*
- * ioctl
- */
- clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(arg1));
+ case FMT_IOCTL_UNMAP:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(event->arg1));
- break;
- }
+ break;
+ }
- case FMT_UNMAP_INFO:
- {
- clen += printf(" D=0x%8.8x B=0x%-10x /dev/%s", arg2, arg3, find_disk_name(arg1));
+ case FMT_UNMAP_INFO:
+ {
+ 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));
- break;
- }
+ break;
+ }
- case FMT_SELECT:
- /*
- * select
- */
- if (arg1)
- clen += printf(" [%3d]", arg1);
- else
- clen += printf(" S=%-3d", arg2);
+ case FMT_SELECT:
+ /*
+ * select
+ */
+ if (event->arg1)
+ clen += printf(" [%3d]", (int)event->arg1);
+ else
+ clen += printf(" S=%-3d", (int)event->arg2);
- break;
+ break;
- case FMT_LSEEK:
- case FMT_PREAD:
- /*
- * pread, pwrite, lseek
- */
- clen += printf(" F=%-3d", ti->arg1);
+ case FMT_LSEEK:
+ case FMT_PREAD:
+ /*
+ * pread, pwrite, lseek
+ */
+ clen += printf(" F=%-3d", (int)ti->arg1);
+
+ if (event->arg1) {
+ clen += printf("[%3d] ", (int)event->arg1);
+ } else {
+ if (format == FMT_PREAD)
+ clen += printf(" B=0x%-8" PRIx64 " ", (uint64_t)event->arg2);
+ else
+ clen += printf(" ");
+ }
- if (arg1)
- clen += printf("[%3d] ", arg1);
- else {
- if (format == FMT_PREAD)
- clen += printf(" B=0x%-8x ", arg2);
+ if (format == FMT_PREAD)
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
else
- clen += printf(" ");
- }
- if (format == FMT_PREAD)
- offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
- else
#ifdef __ppc__
- offset_reassembled = (((off_t)(unsigned int)(arg2)) << 32) | (unsigned int)(arg3);
+ offset_reassembled = (((off_t)(unsigned int)(arg2)) << 32) | (unsigned int)(arg3);
#else
- offset_reassembled = (((off_t)(unsigned int)(arg3)) << 32) | (unsigned int)(arg2);
+ offset_reassembled = (((off_t)(unsigned int)(event->arg3)) << 32) | (unsigned int)(event->arg2);
#endif
- clen += clip_64bit("O=", offset_reassembled);
- if (format == FMT_LSEEK) {
- char *mode;
+ clen += clip_64bit("O=", offset_reassembled);
- if (ti->arg4 == SEEK_SET)
- mode = "SEEK_SET";
- else if (ti->arg4 == SEEK_CUR)
- mode = "SEEK_CUR";
- else if (ti->arg4 == SEEK_END)
- mode = "SEEK_END";
- else
- mode = "UNKNOWN";
-
- clen += printf(" <%s>", mode);
- }
- break;
+ if (format == FMT_LSEEK) {
+ char *mode;
- case FMT_MMAP:
- /*
- * mmap
- */
- clen += printf(" F=%-3d ", ti->arg1);
+ if (ti->arg3 == SEEK_SET)
+ mode = "SEEK_SET";
+ else if (ti->arg3 == SEEK_CUR)
+ mode = "SEEK_CUR";
+ else if (ti->arg3 == SEEK_END)
+ mode = "SEEK_END";
+ else
+ mode = "UNKNOWN";
- if (arg1)
- clen += printf("[%3d] ", arg1);
- else {
+ clen += printf(" <%s>", mode);
+ }
- user_addr = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
+ break;
- clen += clip_64bit("A=", user_addr);
+ case FMT_MMAP:
+ /*
+ * mmap
+ */
+ clen += printf(" F=%-3d ", (int)ti->arg1);
- offset_reassembled = (((off_t)(unsigned int)(ti->arg6)) << 32) | (unsigned int)(ti->arg7);
+ if (event->arg1) {
+ clen += printf("[%3d] ", (int)event->arg1);
+ } else {
+ user_addr = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
- clen += clip_64bit("O=", offset_reassembled);
+ clen += clip_64bit("A=", user_addr);
- user_size = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg5);
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg6)) << 32) | (unsigned int)(ti->arg7);
- clen += printf("B=0x%-16qx", user_size);
-
- clen += printf(" <");
+ clen += clip_64bit("O=", offset_reassembled);
- if (ti->arg8 & PROT_READ)
- clen += printf("READ");
+ user_size = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg5);
- if (ti->arg8 & PROT_WRITE)
- clen += printf("|WRITE");
+ clen += printf("B=0x%-16qx", user_size);
- if (ti->arg8 & PROT_EXEC)
- clen += printf("|EXEC");
+ clen += printf(" <");
- clen += printf(">");
- }
- break;
+ if (ti->arg8 & PROT_READ)
+ clen += printf("READ");
- case FMT_TRUNC:
- case FMT_FTRUNC:
- /*
- * ftruncate, truncate
- */
- if (format == FMT_FTRUNC)
- clen += printf(" F=%-3d", ti->arg1);
- else
- clen += printf(" ");
+ if (ti->arg8 & PROT_WRITE)
+ clen += printf("|WRITE");
+
+ if (ti->arg8 & PROT_EXEC)
+ clen += printf("|EXEC");
+
+ clen += printf(">");
+ }
+
+ break;
+
+ case FMT_TRUNC:
+ case FMT_FTRUNC:
+ /*
+ * ftruncate, truncate
+ */
+ if (format == FMT_FTRUNC)
+ clen += printf(" F=%-3d", (int)ti->arg1);
+ else
+ clen += printf(" ");
- if (arg1)
- clen += printf("[%3d]", arg1);
+ if (event->arg1)
+ clen += printf("[%3d]", (int)event->arg1);
#ifdef __ppc__
- offset_reassembled = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
#else
- offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg2);
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg2);
#endif
- clen += clip_64bit(" O=", offset_reassembled);
+ clen += clip_64bit(" O=", offset_reassembled);
- nopadding = 1;
- break;
+ nopadding = 1;
+ break;
- case FMT_FCHFLAGS:
- case FMT_CHFLAGS:
- {
- /*
- * fchflags, chflags
- */
- int mlen = 0;
+ case FMT_FCHFLAGS:
+ case FMT_CHFLAGS:
+ {
+ /*
+ * fchflags, chflags
+ */
+ int mlen = 0;
+
+ if (format == FMT_FCHFLAGS) {
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
+ } else {
+ if (event->arg1)
+ clen += printf(" [%3d] ", (int)event->arg1);
+ }
+
+ buf[mlen++] = ' ';
+ buf[mlen++] = '<';
+
+ if (ti->arg2 & UF_NODUMP)
+ mlen += sprintf(&buf[mlen], "UF_NODUMP | ");
+ if (ti->arg2 & UF_IMMUTABLE)
+ mlen += sprintf(&buf[mlen], "UF_IMMUTABLE | ");
+ if (ti->arg2 & UF_APPEND)
+ mlen += sprintf(&buf[mlen], "UF_APPEND | ");
+ if (ti->arg2 & UF_OPAQUE)
+ mlen += sprintf(&buf[mlen], "UF_OPAQUE | ");
+ if (ti->arg2 & SF_ARCHIVED)
+ mlen += sprintf(&buf[mlen], "SF_ARCHIVED | ");
+ if (ti->arg2 & SF_IMMUTABLE)
+ mlen += sprintf(&buf[mlen], "SF_IMMUTABLE | ");
+ if (ti->arg2 & SF_APPEND)
+ mlen += sprintf(&buf[mlen], "SF_APPEND | ");
+
+ if (ti->arg2 == 0)
+ mlen += sprintf(&buf[mlen], "CLEAR_ALL_FLAGS | ");
+ else if (ti->arg2 & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen >= 3)
+ mlen -= 3;
+
+ buf[mlen++] = '>';
+ buf[mlen] = '\0';
+
+ if (mlen < 19) {
+ memset(&buf[mlen], ' ', 19 - mlen);
+ mlen = 19;
+ buf[mlen] = '\0';
+ }
+
+ clen += printf("%s", buf);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_UMASK:
+ case FMT_FCHMOD:
+ case FMT_FCHMOD_EXT:
+ case FMT_CHMOD:
+ case FMT_CHMOD_EXT:
+ case FMT_CHMODAT:
+ {
+ /*
+ * fchmod, fchmod_extended, chmod, chmod_extended
+ */
+ uint64_t mode;
+
+ if (format == FMT_FCHMOD || format == FMT_FCHMOD_EXT) {
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d] ", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d ", (int)ti->arg1);
+ } else {
+ if (event->arg1)
+ clen += printf(" [%3d] ", (int)event->arg1);
+ else
+ clen += printf(" ");
+ }
- if (format == FMT_FCHFLAGS) {
- if (arg1)
- clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ if (format == FMT_UMASK)
+ mode = ti->arg1;
+ else if (format == FMT_FCHMOD || format == FMT_CHMOD || format == FMT_CHMODAT)
+ mode = ti->arg2;
else
- clen += printf(" F=%-3d", ti->arg1);
- } else {
- if (arg1)
- clen += printf(" [%3d] ", arg1);
+ mode = ti->arg4;
+
+ get_mode_string(mode, &buf[0]);
+
+ if (event->arg1 == 0)
+ clen += printf("<%s> ", buf);
+ else
+ clen += printf("<%s>", buf);
+ break;
+ }
+
+ case FMT_ACCESS:
+ {
+ /*
+ * access
+ */
+ char mode[5];
+
+ memset(mode, '_', 4);
+ mode[4] = '\0';
+
+ if (ti->arg2 & R_OK)
+ mode[0] = 'R';
+ if (ti->arg2 & W_OK)
+ mode[1] = 'W';
+ if (ti->arg2 & X_OK)
+ mode[2] = 'X';
+ if (ti->arg2 == F_OK)
+ mode[3] = 'F';
+
+ if (event->arg1)
+ clen += printf(" [%3d] (%s) ", (int)event->arg1, mode);
+ else
+ clen += printf(" (%s) ", mode);
+
+ nopadding = 1;
+ break;
}
- buf[mlen++] = ' ';
- buf[mlen++] = '<';
-
- if (ti->arg2 & UF_NODUMP)
- mlen += sprintf(&buf[mlen], "UF_NODUMP | ");
- if (ti->arg2 & UF_IMMUTABLE)
- mlen += sprintf(&buf[mlen], "UF_IMMUTABLE | ");
- if (ti->arg2 & UF_APPEND)
- mlen += sprintf(&buf[mlen], "UF_APPEND | ");
- if (ti->arg2 & UF_OPAQUE)
- mlen += sprintf(&buf[mlen], "UF_OPAQUE | ");
- if (ti->arg2 & SF_ARCHIVED)
- mlen += sprintf(&buf[mlen], "SF_ARCHIVED | ");
- if (ti->arg2 & SF_IMMUTABLE)
- mlen += sprintf(&buf[mlen], "SF_IMMUTABLE | ");
- if (ti->arg2 & SF_APPEND)
- mlen += sprintf(&buf[mlen], "SF_APPEND | ");
-
- if (ti->arg2 == 0)
- mlen += sprintf(&buf[mlen], "CLEAR_ALL_FLAGS | ");
- else if (ti->arg2 & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND))
- mlen += sprintf(&buf[mlen], "UNKNOWN | ");
-
- if (mlen >= 3)
- mlen -= 3;
-
- buf[mlen++] = '>';
- buf[mlen] = '\0';
-
- if (mlen < 19) {
- memset(&buf[mlen], ' ', 19 - mlen);
- mlen = 19;
+
+ case FMT_MOUNT:
+ {
+ if (event->arg1)
+ clen += printf(" [%3d] <FLGS=0x%" PRIx64 "> ", (int)event->arg1, ti->arg3);
+ else
+ clen += printf(" <FLGS=0x%" PRIx64 "> ", ti->arg3);
+
+ nopadding = 1;
+ break;
}
- clen += printf("%s", buf);
- nopadding = 1;
- break;
- }
-
- case FMT_UMASK:
- case FMT_FCHMOD:
- case FMT_FCHMOD_EXT:
- case FMT_CHMOD:
- case FMT_CHMOD_EXT:
- {
- /*
- * fchmod, fchmod_extended, chmod, chmod_extended
- */
- int mode;
+ case FMT_UNMOUNT:
+ {
+ char *mountflag;
- if (format == FMT_FCHMOD || format == FMT_FCHMOD_EXT) {
- if (arg1)
- clen += printf(" F=%-3d[%3d] ", ti->arg1, arg1);
+ if (ti->arg2 & MNT_FORCE)
+ mountflag = "<FORCE>";
else
- clen += printf(" F=%-3d ", ti->arg1);
- } else {
- if (arg1)
- clen += printf(" [%3d] ", arg1);
- else
- clen += printf(" ");
+ mountflag = "";
+
+ if (event->arg1)
+ clen += printf(" [%3d] %s ", (int)event->arg1, mountflag);
+ else
+ clen += printf(" %s ", mountflag);
+
+ nopadding = 1;
+ break;
}
- if (format == FMT_UMASK)
- mode = ti->arg1;
- else if (format == FMT_FCHMOD || format == FMT_CHMOD)
- mode = ti->arg2;
- else
- mode = ti->arg4;
- get_mode_string(mode, &buf[0]);
+ case FMT_OPEN:
+ clen += print_open(event, ti->arg2);
+ nopadding = 1;
+ break;
- if (arg1 == 0)
- clen += printf("<%s> ", buf);
- else
- clen += printf("<%s>", buf);
- break;
- }
+ case FMT_OPENAT:
+ clen += print_open(event, ti->arg3);
+ nopadding = 1;
+ break;
- case FMT_ACCESS:
- {
- /*
- * access
- */
- char mode[5];
-
- memset(mode, '_', 4);
- mode[4] = '\0';
-
- if (ti->arg2 & R_OK)
- mode[0] = 'R';
- if (ti->arg2 & W_OK)
- mode[1] = 'W';
- if (ti->arg2 & X_OK)
- mode[2] = 'X';
- if (ti->arg2 == F_OK)
- mode[3] = 'F';
-
- if (arg1)
- clen += printf(" [%3d] (%s) ", arg1, mode);
- else
- clen += printf(" (%s) ", mode);
+ case FMT_GUARDED_OPEN:
+ clen += print_open(event, ti->arg4);
+ nopadding = 1;
+ break;
- nopadding = 1;
- break;
- }
-
- case FMT_MOUNT:
- {
- if (arg1)
- clen += printf(" [%3d] <FLGS=0x%x> ", arg1, ti->arg3);
- else
- clen += printf(" <FLGS=0x%x> ", ti->arg3);
-
- nopadding = 1;
- break;
- }
-
- case FMT_UNMOUNT:
- {
- char *mountflag;
-
- if (ti->arg2 & MNT_FORCE)
- mountflag = "<FORCE>";
- else
- mountflag = "";
-
- if (arg1)
- clen += printf(" [%3d] %s ", arg1, mountflag);
- else
- clen += printf(" %s ", mountflag);
-
- nopadding = 1;
- break;
- }
-
- case FMT_OPEN:
- {
- /*
- * open
- */
- char mode[7];
-
- memset(mode, '_', 6);
- mode[6] = '\0';
-
- if (ti->arg2 & O_RDWR) {
- mode[0] = 'R';
- mode[1] = 'W';
- } else if (ti->arg2 & O_WRONLY)
- mode[1] = 'W';
- else
- mode[0] = 'R';
-
- if (ti->arg2 & O_CREAT)
- mode[2] = 'C';
-
- if (ti->arg2 & O_APPEND)
- mode[3] = 'A';
-
- if (ti->arg2 & O_TRUNC)
- mode[4] = 'T';
-
- if (ti->arg2 & O_EXCL)
- mode[5] = 'E';
-
- if (arg1)
- clen += printf(" [%3d] (%s) ", arg1, mode);
- else
- clen += printf(" F=%-3d (%s) ", arg2, mode);
+ case FMT_SOCKET:
+ {
+ /*
+ * socket
+ *
+ */
+ char *domain;
+ char *type;
- nopadding = 1;
- break;
- }
+ switch (ti->arg1) {
+ case AF_UNIX:
+ domain = "AF_UNIX";
+ break;
- case FMT_SOCKET:
- {
- /*
- * socket
- *
- */
- char *domain;
- char *type;
-
- switch (ti->arg1) {
+ case AF_INET:
+ domain = "AF_INET";
+ break;
- case AF_UNIX:
- domain = "AF_UNIX";
- break;
+ case AF_ISO:
+ domain = "AF_ISO";
+ break;
- case AF_INET:
- domain = "AF_INET";
- break;
+ case AF_NS:
+ domain = "AF_NS";
+ break;
- case AF_ISO:
- domain = "AF_ISO";
- break;
+ case AF_IMPLINK:
+ domain = "AF_IMPLINK";
+ break;
- case AF_NS:
- domain = "AF_NS";
- break;
+ default:
+ domain = "UNKNOWN";
+ break;
+ }
- case AF_IMPLINK:
- domain = "AF_IMPLINK";
- break;
+ switch (ti->arg2) {
+ case SOCK_STREAM:
+ type = "SOCK_STREAM";
+ break;
+ case SOCK_DGRAM:
+ type = "SOCK_DGRAM";
+ break;
+ case SOCK_RAW:
+ type = "SOCK_RAW";
+ break;
+ default:
+ type = "UNKNOWN";
+ break;
+ }
- default:
- domain = "UNKNOWN";
- break;
- }
+ if (event->arg1)
+ clen += printf(" [%3d] <%s, %s, 0x%" PRIx64 ">", (int)event->arg1, domain, type, ti->arg3);
+ else
+ clen += printf(" F=%-3d <%s, %s, 0x%" PRIx64 ">", (int)event->arg2, domain, type, ti->arg3);
- switch (ti->arg2) {
-
- case SOCK_STREAM:
- type = "SOCK_STREAM";
- break;
+ break;
+ }
- case SOCK_DGRAM:
- type = "SOCK_DGRAM";
- break;
+ case FMT_AIO_FSYNC:
+ {
+ /*
+ * aio_fsync [errno] AIOCBP OP
+ */
+ char *op;
- case SOCK_RAW:
- type = "SOCK_RAW";
- break;
+ if (ti->arg1 == O_SYNC || ti->arg1 == 0)
+ op = "AIO_FSYNC";
+#if O_DSYNC
+ else if (ti->arg1 == O_DSYNC)
+ op = "AIO_DSYNC";
+#endif
+ else
+ op = "UNKNOWN";
- case SOCK_SEQPACKET:
- type = "SOCK_SEQPACKET";
- break;
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8.8" PRIx64 " <%s>", (int)event->arg1, ti->arg2, op);
+ else
+ clen += printf(" P=0x%8.8" PRIx64 " <%s>", ti->arg2, op);
- case SOCK_RDM:
- type = "SOCK_RDM";
- break;
-
- default:
- type = "UNKNOWN";
- break;
+ break;
}
- if (arg1)
- clen += printf(" [%3d] <%s, %s, 0x%x>", arg1, domain, type, ti->arg3);
- else
- clen += printf(" F=%-3d <%s, %s, 0x%x>", arg2, domain, type, ti->arg3);
- break;
- }
+ case FMT_AIO_RETURN:
+ /*
+ * aio_return [errno] AIOCBP IOSIZE
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8.8" PRIx64, (int)event->arg1, ti->arg1);
+ else
+ clen += printf(" P=0x%8.8" PRIx64 " B=0x%-8" PRIx64, ti->arg1, (uint64_t)event->arg2);
- case FMT_AIO_FSYNC:
- {
- /*
- * aio_fsync [errno] AIOCBP OP
- */
- char *op;
+ break;
- if (ti->arg1 == O_SYNC || ti->arg1 == 0)
- op = "AIO_FSYNC";
-#if O_DSYNC
- else if (ti->arg1 == O_DSYNC)
- op = "AIO_DSYNC";
-#endif
- else
- op = "UNKNOWN";
+ case FMT_AIO_SUSPEND:
+ /*
+ * aio_suspend [errno] NENTS
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] N=%d", (int)event->arg1, (int)ti->arg2);
+ else
+ clen += printf(" N=%d", (int)ti->arg2);
- if (arg1)
- clen += printf(" [%3d] P=0x%8.8x <%s>", arg1, ti->arg2, op);
- else
- clen += printf(" P=0x%8.8x <%s>", ti->arg2, op);
- break;
- }
+ break;
- case FMT_AIO_RETURN:
- /*
- * aio_return [errno] AIOCBP IOSIZE
- */
- if (arg1)
- clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg1);
- else
- clen += printf(" P=0x%8.8x B=0x%-8x", ti->arg1, arg2);
- break;
+ case FMT_AIO_CANCEL:
+ /*
+ * aio_cancel [errno] FD or AIOCBP (if non-null)
+ */
+ if (ti->arg2) {
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8." PRIx64, (int)event->arg1, ti->arg2);
+ else
+ clen += printf(" P=0x%8.8" PRIx64, ti->arg2);
+ } else {
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
+ }
- case FMT_AIO_SUSPEND:
- /*
- * aio_suspend [errno] NENTS
- */
- if (arg1)
- clen += printf(" [%3d] N=%d", arg1, ti->arg2);
- else
- clen += printf(" N=%d", ti->arg2);
- break;
+ break;
- case FMT_AIO_CANCEL:
- /*
- * aio_cancel [errno] FD or AIOCBP (if non-null)
- */
- if (ti->arg2) {
- if (arg1)
- clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg2);
- else
- clen += printf(" P=0x%8.8x", ti->arg2);
- } else {
- if (arg1)
- clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ case FMT_AIO:
+ /*
+ * aio_error, aio_read, aio_write [errno] AIOCBP
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8.8" PRIx64, (int)event->arg1, ti->arg1);
else
- clen += printf(" F=%-3d", ti->arg1);
- }
- break;
+ clen += printf(" P=0x%8.8" PRIx64, ti->arg1);
- case FMT_AIO:
- /*
- * aio_error, aio_read, aio_write [errno] AIOCBP
- */
- if (arg1)
- clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg1);
- else
- clen += printf(" P=0x%8.8x", ti->arg1);
- break;
+ break;
- case FMT_LIO_LISTIO:
- {
- /*
- * lio_listio [errno] NENTS MODE
- */
- char *op;
+ case FMT_LIO_LISTIO: {
+ /*
+ * lio_listio [errno] NENTS MODE
+ */
+ char *op;
- if (ti->arg1 == LIO_NOWAIT)
- op = "LIO_NOWAIT";
- else if (ti->arg1 == LIO_WAIT)
- op = "LIO_WAIT";
- else
- op = "UNKNOWN";
+ if (ti->arg1 == LIO_NOWAIT)
+ op = "LIO_NOWAIT";
+ else if (ti->arg1 == LIO_WAIT)
+ op = "LIO_WAIT";
+ else
+ op = "UNKNOWN";
- if (arg1)
- clen += printf(" [%3d] N=%d <%s>", arg1, ti->arg3, op);
- else
- clen += printf(" N=%d <%s>", ti->arg3, op);
- break;
- }
+ if (event->arg1)
+ clen += printf(" [%3d] N=%d <%s>", (int)event->arg1, (int)ti->arg3, op);
+ else
+ clen += printf(" N=%d <%s>", (int)ti->arg3, op);
+ break;
+ }
}
}
* Calculate space available to print pathname
*/
if (columns > MAXCOLS || wideflag)
- clen = columns - (clen + 14 + 20 + 11);
+ clen = columns - (clen + 14 + 20 + 11);
else
- clen = columns - (clen + 14 + 12);
-
- if (class != FILEMGR_CLASS && !nopadding)
- clen -= 3;
-
- if (framework_name)
- len = sprintf(&buf[0], " %s %s ", framework_type, framework_name);
- else if (*pathname != '\0') {
- len = sprintf(&buf[0], " %s ", pathname);
+ clen = columns - (clen + 14 + 12);
+
+ if (!nopadding)
+ clen -= 3;
+
+ if (framework_name) {
+ len = sprintf(&buf[0], " %s %s ", framework_type, framework_name);
+ } else if (*pathname != '\0') {
+ switch(format) {
+ case FMT_AT:
+ case FMT_OPENAT:
+ case FMT_CHMODAT:
+ len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg1, pathname);
+ break;
+ case FMT_RENAMEAT:
+ len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg3, pathname);
+ break;
+ default:
+ len = sprintf(&buf[0], " %s ", pathname);
+ }
- if (format == FMT_MOUNT && ti->pathname2[0]) {
+ if (format == FMT_MOUNT && ti->pathname2[0] != '\0') {
int len2;
memset(&buf[len], ' ', 2);
- len2 = sprintf(&buf[len+2], " %s ", (char *)ti->pathname2);
+ len2 = sprintf(&buf[len+2], " %s ", ti->pathname2);
len = len + 2 + len2;
}
- } else
- len = 0;
+ } else {
+ len = 0;
+ }
if (clen > len) {
- /*
+ /*
* Add null padding if column length
* is wider than the pathname length.
*/
- memset(&buf[len], ' ', clen - len);
+ memset(&buf[len], ' ', clen - len);
buf[clen] = '\0';
pathname = buf;
-
} else if (clen == len) {
- pathname = buf;
-
+ pathname = buf;
} else if ((clen > 0) && (clen < len)) {
- /*
+ /*
* This prints the tail end of the pathname
*/
- buf[len-clen] = ' ';
+ buf[len-clen] = ' ';
pathname = &buf[len - clen];
-
} else {
- pathname = "";
+ pathname = "";
}
-
+
/*
- * fudge some additional system call overhead
+ * fudge some additional system call overhead
* that currently isn't tracked... this also
- * insures that we see a minimum of 1 us for
+ * insures that we see a minimum of 1 us for
* an elapsed time
*/
- usecs = (unsigned long)(((now - stime) + (divisor-1)) / divisor);
- secs = usecs / 1000000;
- usecs -= secs * 1000000;
+ usecs = (mach_to_nano(now - stime) + (NSEC_PER_USEC - 1)) / NSEC_PER_USEC;
+ secs = usecs / USEC_PER_SEC;
+ usecs -= secs * USEC_PER_SEC;
- if (class != FILEMGR_CLASS && !nopadding)
- p1 = " ";
+ if (!nopadding)
+ p1 = " ";
else
- p1 = "";
-
+ p1 = "";
+
if (waited)
- p2 = " W";
+ p2 = " W";
else
- p2 = " ";
+ p2 = " ";
if (columns > MAXCOLS || wideflag)
- printf("%s%s %3ld.%06ld%s %s.%d\n", p1, pathname, (unsigned long)secs, (unsigned long)usecs, p2, command_name, (int)thread);
+ printf("%s%s %3llu.%06llu%s %s.%" PRIu64 "\n", p1, pathname, secs, usecs, p2, command_name, threadid);
else
- printf("%s%s %3ld.%06ld%s %-12.12s\n", p1, pathname, (unsigned long)secs, (unsigned long)usecs, p2, command_name);
+ printf("%s%s %3llu.%06llu%s %-12.12s\n", p1, pathname, secs, usecs, p2, command_name);
+
+ if (!RAW_flag)
+ fflush(stdout);
}
+#pragma mark metadata info hash routines
+
+#define VN_HASH_SIZE 16384
+#define VN_HASH_MASK (VN_HASH_SIZE - 1)
+
+typedef struct meta_info {
+ struct meta_info *m_next;
+ uint64_t m_blkno;
+ char m_name[MAXPATHLEN];
+} *meta_info_t;
+
+meta_info_t m_info_hash[VN_HASH_SIZE];
void
-delete_event(th_info_t ti_to_delete) {
- th_info_t ti;
- th_info_t ti_prev;
- int hashid;
+meta_add_name(uint64_t blockno, const char *pathname)
+{
+ meta_info_t mi;
+ int hashid;
- hashid = ti_to_delete->thread & HASH_MASK;
+ hashid = blockno & VN_HASH_MASK;
- if ((ti = th_info_hash[hashid])) {
- if (ti == ti_to_delete)
- th_info_hash[hashid] = ti->next;
- else {
- ti_prev = ti;
+ for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
+ if (mi->m_blkno == blockno)
+ break;
+ }
- for (ti = ti->next; ti; ti = ti->next) {
- if (ti == ti_to_delete) {
- ti_prev->next = ti->next;
- break;
- }
- ti_prev = ti;
- }
- }
- if (ti) {
- ti->next = th_info_freelist;
- th_info_freelist = ti;
- }
- }
+ if (mi == NULL) {
+ mi = malloc(sizeof (struct meta_info));
+
+ mi->m_next = m_info_hash[hashid];
+ m_info_hash[hashid] = mi;
+ mi->m_blkno = blockno;
+ }
+
+ strncpy(mi->m_name, pathname, sizeof (mi->m_name));
}
-th_info_t
-add_event(uintptr_t thread, int type) {
- th_info_t ti;
+const char *
+meta_find_name(uint64_t blockno)
+{
+ meta_info_t mi;
int hashid;
+ hashid = blockno & VN_HASH_MASK;
+
+ for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
+ if (mi->m_blkno == blockno)
+ return mi->m_name;
+ }
+
+ return "";
+}
+
+void
+meta_delete_all(void)
+{
+ meta_info_t mi, next;
+ int i;
+
+ for (i = 0; i < HASH_MASK; i++) {
+ for (mi = m_info_hash[i]; mi; mi = next) {
+ next = mi->m_next;
+
+ free(mi);
+ }
+
+ m_info_hash[i] = NULL;
+ }
+}
+
+#pragma mark event ("thread info") routines
+
+th_info_t th_info_hash[HASH_SIZE];
+th_info_t th_info_freelist;
+
+static th_info_t
+add_event(ktrace_event_t event, int type)
+{
+ th_info_t ti;
+ int hashid;
+ uint64_t eventid;
+
if ((ti = th_info_freelist))
th_info_freelist = ti->next;
else
- ti = (th_info_t)malloc(sizeof(struct th_info));
+ ti = malloc(sizeof (struct th_info));
- hashid = thread & HASH_MASK;
+ bzero(ti, sizeof (struct th_info));
+
+ hashid = event->threadid & HASH_MASK;
ti->next = th_info_hash[hashid];
th_info_hash[hashid] = ti;
- ti->thread = thread;
- ti->type = type;
+ eventid = event->debugid & KDBG_EVENTID_MASK;
+
+ if (eventid == BSC_execve || eventid == BSC_posix_spawn) {
+ const char *command;
+
+ command = ktrace_get_execname_for_thread(s, event->threadid);
- ti->waited = 0;
- ti->in_filemgr = 0;
- ti->pathptr = ti->pathname;
- ti->pathname[0] = 0;
- ti->pathname2[0] = 0;
+ if (!command)
+ command = "";
+
+ strncpy(ti->command, command, sizeof (ti->command));
+ ti->command[MAXCOMLEN] = '\0';
+ }
+
+ ti->thread = event->threadid;
+ ti->type = type;
- return (ti);
+ return ti;
}
th_info_t
-find_event(uintptr_t thread, int type) {
- th_info_t ti;
- int hashid;
+event_find(uint64_t thread, int type)
+{
+ th_info_t ti;
+ int hashid;
hashid = thread & HASH_MASK;
for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
if (ti->thread == thread) {
- if (type == ti->type)
- return (ti);
- if (ti->in_filemgr) {
- if (type == -1)
- return (ti);
- continue;
- }
+ if (type == ti->type)
+ return ti;
+
if (type == 0)
- return (ti);
+ return ti;
}
}
- return ((th_info_t) 0);
-}
-void
-delete_all_events() {
- th_info_t ti = 0;
- th_info_t ti_next = 0;
- int i;
-
- for (i = 0; i < HASH_SIZE; i++) {
-
- for (ti = th_info_hash[i]; ti; ti = ti_next) {
- ti_next = ti->next;
- ti->next = th_info_freelist;
- th_info_freelist = ti;
- }
- th_info_hash[i] = 0;
- }
+ return NULL;
}
-
void
-mark_thread_waited(uintptr_t thread) {
- th_info_t ti;
- int hashid;
-
- hashid = thread & HASH_MASK;
-
- for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
- if (ti->thread == thread)
- ti->waited = 1;
- }
-}
-
-
-void read_command_map()
+event_delete(th_info_t ti_to_delete)
{
- size_t size;
- int i;
- int total_threads = 0;
- kd_threadmap *mapptr = 0;
-
- delete_all_map_entries();
-
- if (!RAW_flag) {
+ th_info_t ti;
+ th_info_t ti_prev;
+ int hashid;
- total_threads = bufinfo.nkdthreads;
- size = bufinfo.nkdthreads * sizeof(kd_threadmap);
+ hashid = ti_to_delete->thread & HASH_MASK;
- if (size) {
- if ((mapptr = (kd_threadmap *) malloc(size))) {
- int mib[6];
+ if ((ti = th_info_hash[hashid])) {
+ if (ti == ti_to_delete)
+ th_info_hash[hashid] = ti->next;
+ else {
+ ti_prev = ti;
- bzero (mapptr, size);
- /*
- * Now read the threadmap
- */
- mib[0] = CTL_KERN;
- mib[1] = KERN_KDEBUG;
- mib[2] = KERN_KDTHRMAP;
- mib[3] = 0;
- mib[4] = 0;
- mib[5] = 0; /* no flags */
-
- if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0) {
- /*
- * This is not fatal -- just means I cant map command strings
- */
- free(mapptr);
- return;
+ for (ti = ti->next; ti; ti = ti->next) {
+ if (ti == ti_to_delete) {
+ ti_prev->next = ti->next;
+ break;
}
+ ti_prev = ti;
}
}
- } else {
- RAW_header header;
- off_t offset;
-
- RAW_fd = open(RAW_file, O_RDONLY);
-
- if (RAW_fd < 0) {
- perror("Can't open RAW file");
- exit(1);
- }
- if (read(RAW_fd, &header, sizeof(RAW_header)) != sizeof(RAW_header)) {
- perror("read failed");
- exit(2);
+ if (ti) {
+ ti->next = th_info_freelist;
+ th_info_freelist = ti;
}
- if (header.version_no != RAW_VERSION1) {
- header.version_no = RAW_VERSION0;
- header.TOD_secs = time((long *)0);
- header.TOD_usecs = 0;
+ }
+}
+
+void
+event_delete_all(void)
+{
+ th_info_t ti = 0;
+ th_info_t ti_next = 0;
+ int i;
- lseek(RAW_fd, (off_t)0, SEEK_SET);
+ for (i = 0; i < HASH_SIZE; i++) {
- if (read(RAW_fd, &header.thread_count, sizeof(int)) != sizeof(int)) {
- perror("read failed");
- exit(2);
- }
+ for (ti = th_info_hash[i]; ti; ti = ti_next) {
+ ti_next = ti->next;
+ ti->next = th_info_freelist;
+ th_info_freelist = ti;
}
- sample_TOD_secs = header.TOD_secs;
- sample_TOD_usecs = header.TOD_usecs;
+ th_info_hash[i] = 0;
+ }
+}
- total_threads = header.thread_count;
- size = total_threads * sizeof(kd_threadmap);
+void
+event_enter(int type, ktrace_event_t event)
+{
+ th_info_t ti;
- if (size) {
- if ((mapptr = (kd_threadmap *) malloc(size))) {
- bzero (mapptr, size);
+#if DEBUG
+ int index;
+ bool found;
- if (read(RAW_fd, mapptr, size) != size) {
- free(mapptr);
- return;
- }
- }
- }
- if (header.version_no != RAW_VERSION0) {
- offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
- offset = (offset + (4095)) & ~4095;
+ found = false;
- lseek(RAW_fd, offset, SEEK_SET);
- }
+ switch (type) {
+ case P_CS_SYNC_DISK:
+ case MACH_pageout:
+ case MACH_vmfault:
+ case MSC_map_fd:
+ case SPEC_ioctl:
+ case Throttled:
+ case HFS_update:
+ found = true;
}
- for (i = 0; i < total_threads; i++)
- create_map_entry(mapptr[i].thread, mapptr[i].valid, &mapptr[i].command[0]);
-
- free(mapptr);
-}
+ if ((type & CSC_MASK) == BSC_BASE) {
+ if ((index = BSC_INDEX(type)) < MAX_BSD_SYSCALL && bsd_syscalls[index].sc_name)
+ found = true;
+ }
-void delete_all_map_entries()
-{
- threadmap_t tme = 0;
- threadmap_t tme_next = 0;
- int i;
+ os_assert(found);
+#endif /* DEBUG */
- for (i = 0; i < HASH_SIZE; i++) {
+ if ((ti = add_event(event, type)) == NULL)
+ return;
- for (tme = threadmap_hash[i]; tme; tme = tme_next) {
- if (tme->tm_setptr)
- free(tme->tm_setptr);
- tme_next = tme->tm_next;
- tme->tm_next = threadmap_freelist;
- threadmap_freelist = tme;
- }
- threadmap_hash[i] = 0;
- }
+ ti->stime = event->timestamp;
+ ti->arg1 = event->arg1;
+ ti->arg2 = event->arg2;
+ ti->arg3 = event->arg3;
+ ti->arg4 = event->arg4;
}
-
-void create_map_entry(uintptr_t thread, int pid, char *command)
+void
+event_exit(char *sc_name, int type, ktrace_event_t event, int format)
{
- threadmap_t tme;
- int hashid;
+ th_info_t ti;
+ pid_t pid;
+
+ if ((ti = event_find(event->threadid, type)) == NULL)
+ return;
- if ((tme = threadmap_freelist))
- threadmap_freelist = tme->tm_next;
- else
- tme = (threadmap_t)malloc(sizeof(struct threadmap));
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
- tme->tm_thread = thread;
- tme->tm_setsize = 0;
- tme->tm_setptr = 0;
+ if (check_filter_mode(pid, ti, type, (int)event->arg1, (int)event->arg2, sc_name)) {
+ const char *pathname;
- (void)strncpy (tme->tm_command, command, MAXCOMLEN);
- tme->tm_command[MAXCOMLEN] = '\0';
+ pathname = NULL;
- hashid = thread & HASH_MASK;
+ /* most things are just interested in the first lookup */
+ if (ti->pathname[0] != '\0')
+ pathname = ti->pathname;
- tme->tm_next = threadmap_hash[hashid];
- threadmap_hash[hashid] = tme;
+ if (!pathname)
+ pathname = "";
- if (pid != 0 && pid != 1) {
- if (!strncmp(command, "LaunchCFMA", 10))
- (void)get_real_command_name(pid, tme->tm_command, MAXCOMLEN);
+ format_print(ti, sc_name, event, type, format, event->timestamp, ti->stime, ti->waited, pathname, NULL);
}
-}
+ event_delete(ti);
+}
-threadmap_t
-find_map_entry(uintptr_t thread)
+void
+event_mark_thread_waited(uint64_t thread)
{
- threadmap_t tme;
- int hashid;
+ th_info_t ti;
+ int hashid;
hashid = thread & HASH_MASK;
- for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
- if (tme->tm_thread == thread)
- return (tme);
+ for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
+ if (ti->thread == thread)
+ ti->waited = 1;
}
- return (0);
}
+#pragma mark network fd set routines
-void
-delete_map_entry(uintptr_t thread)
+struct pid_fd_set {
+ struct pid_fd_set *next;
+ pid_t pid;
+ char *set;
+ size_t setsize; /* number of *bytes*, not bits */
+};
+
+struct pid_fd_set *pfs_hash[HASH_SIZE];
+
+static struct pid_fd_set *
+pfs_get(pid_t pid)
{
- threadmap_t tme = 0;
- threadmap_t tme_prev;
- int hashid;
-
- hashid = thread & HASH_MASK;
-
- if ((tme = threadmap_hash[hashid])) {
- if (tme->tm_thread == thread)
- threadmap_hash[hashid] = tme->tm_next;
- else {
- tme_prev = tme;
-
- for (tme = tme->tm_next; tme; tme = tme->tm_next) {
- if (tme->tm_thread == thread) {
- tme_prev->tm_next = tme->tm_next;
- break;
- }
- tme_prev = tme;
- }
- }
- if (tme) {
- if (tme->tm_setptr)
- free(tme->tm_setptr);
+ struct pid_fd_set *pfs;
+ int hashid;
- tme->tm_next = threadmap_freelist;
- threadmap_freelist = tme;
+ os_assert(pid >= 0);
+
+ hashid = pid & HASH_MASK;
+
+ for (pfs = pfs_hash[hashid]; pfs; pfs = pfs->next) {
+ if (pfs->pid == pid) {
+ return pfs;
}
}
-}
+ pfs = calloc(1, sizeof (struct pid_fd_set));
+
+ pfs->pid = pid;
+ pfs->set = NULL;
+ pfs->setsize = 0;
+ pfs->next = pfs_hash[hashid];
+ pfs_hash[hashid] = pfs;
+
+ return pfs;
+}
void
-fs_usage_fd_set(uintptr_t thread, unsigned int fd)
+fd_clear_pid(pid_t pid)
{
- threadmap_t tme;
+ struct pid_fd_set *pfs, *prev;
+ int hashid;
- if ((tme = find_map_entry(thread)) == 0)
+ if (pid < 0)
return;
- /*
- * If the map is not allocated, then now is the time
- */
- if (tme->tm_setptr == (unsigned long *)0) {
- if ((tme->tm_setptr = (unsigned long *)malloc(FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE))) == 0)
- return;
- tme->tm_setsize = FS_USAGE_FD_SETSIZE;
- bzero(tme->tm_setptr, (FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE)));
- }
- /*
- * If the map is not big enough, then reallocate it
- */
- while (tme->tm_setsize <= fd) {
- int n;
+ hashid = pid & HASH_MASK;
- n = tme->tm_setsize * 2;
- tme->tm_setptr = (unsigned long *)realloc(tme->tm_setptr, (FS_USAGE_NFDBYTES(n)));
+ pfs = pfs_hash[hashid];
+ prev = NULL;
- bzero(&tme->tm_setptr[(tme->tm_setsize/FS_USAGE_NFDBITS)], (FS_USAGE_NFDBYTES(tme->tm_setsize)));
- tme->tm_setsize = n;
+ while (pfs) {
+ if (pfs->pid == pid) {
+ if (prev) {
+ prev->next = pfs->next;
+ } else {
+ pfs_hash[hashid] = pfs->next;
+ }
+
+ free(pfs->set);
+ free(pfs);
+
+ break;
+ } else {
+ prev = pfs;
+ pfs = pfs->next;
+ }
}
- /*
- * set the bit
- */
- tme->tm_setptr[fd/FS_USAGE_NFDBITS] |= (1 << ((fd) % FS_USAGE_NFDBITS));
}
-
-/*
- * Return values:
- * 0 : File Descriptor bit is not set
- * 1 : File Descriptor bit is set
- */
-int
-fs_usage_fd_isset(uintptr_t thread, unsigned int fd)
+void
+fd_clear_all(void)
{
- threadmap_t tme;
- int ret = 0;
+ struct pid_fd_set *pfs, *next;
+ int i;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+ for (pfs = pfs_hash[i]; pfs; pfs = next) {
+ next = pfs->next;
+
+ free(pfs->set);
+ free(pfs);
+ }
- if ((tme = find_map_entry(thread))) {
- if (tme->tm_setptr && fd < tme->tm_setsize)
- ret = tme->tm_setptr[fd/FS_USAGE_NFDBITS] & (1 << (fd % FS_USAGE_NFDBITS));
+ pfs_hash[i] = NULL;
}
- return (ret);
}
-
void
-fs_usage_fd_clear(uintptr_t thread, unsigned int fd)
+fd_set_is_network(pid_t pid, uint64_t fd, bool set)
{
- threadmap_t tme;
+ struct pid_fd_set *pfs;
- if ((tme = find_map_entry(thread))) {
- if (tme->tm_setptr && fd < tme->tm_setsize)
- tme->tm_setptr[fd/FS_USAGE_NFDBITS] &= ~(1 << (fd % FS_USAGE_NFDBITS));
- }
-}
+ if (pid < 0)
+ return;
+ if (fd > OPEN_MAX)
+ return;
+ pfs = pfs_get(pid);
+ if (fd >= pfs->setsize * CHAR_BIT) {
+ size_t newsize;
-void
-argtopid(char *str)
+ if (!set) return;
+
+ newsize = MAX(((size_t)fd + CHAR_BIT) / CHAR_BIT, 2 * pfs->setsize);
+ pfs->set = reallocf(pfs->set, newsize);
+ os_assert(pfs->set != NULL);
+
+ bzero(pfs->set + pfs->setsize, newsize - pfs->setsize);
+ pfs->setsize = newsize;
+ }
+
+ if (set)
+ setbit(pfs->set, fd);
+ else
+ clrbit(pfs->set, fd);
+}
+
+bool
+fd_is_network(pid_t pid, uint64_t fd)
{
- char *cp;
- int ret;
- int i;
+ struct pid_fd_set *pfs;
- ret = (int)strtol(str, &cp, 10);
+ if (pid < 0)
+ return false;
- if (cp == str || *cp) {
- /*
- * Assume this is a command string and find matching pids
- */
- if (!kp_buffer)
- find_proc_names();
+ pfs = pfs_get(pid);
- for (i = 0; i < kp_nentries && num_of_pids < (MAX_PIDS - 1); i++) {
- if (kp_buffer[i].kp_proc.p_stat == 0)
- continue;
- else {
- if (!strncmp(str, kp_buffer[i].kp_proc.p_comm,
- sizeof(kp_buffer[i].kp_proc.p_comm) -1))
- pids[num_of_pids++] = kp_buffer[i].kp_proc.p_pid;
- }
- }
+ if (fd >= pfs->setsize * CHAR_BIT) {
+ return false;
}
- else if (num_of_pids < (MAX_PIDS - 1))
- pids[num_of_pids++] = ret;
+
+ return isset(pfs->set, fd);
}
+#pragma mark shared region address lookup routines
+#define MAXINDEX 2048
-void
-lookup_name(uint64_t user_addr, char **type, char **name)
-{
- int i;
- int start, last;
-
- *name = NULL;
- *type = NULL;
+struct library_range {
+ uint64_t b_address;
+ uint64_t e_address;
+};
- if (numFrameworks) {
+struct library_info {
+ uint64_t b_address;
+ uint64_t e_address;
+ int r_type;
+ char *name;
+};
- if ((user_addr >= framework32.b_address && user_addr < framework32.e_address) ||
- (user_addr >= framework64.b_address && user_addr < framework64.e_address)) {
-
- start = 0;
- last = numFrameworks;
+struct library_range framework32 = {0, 0};
+struct library_range framework64 = {0, 0};
+struct library_range framework64h = {0, 0};
- for (i = numFrameworks / 2; start < last; i = start + ((last - start) / 2)) {
- if (user_addr > frameworkInfo[i].e_address)
- start = i+1;
- else
- last = i;
- }
- if (start < numFrameworks &&
- user_addr >= frameworkInfo[start].b_address && user_addr < frameworkInfo[start].e_address) {
- *type = frameworkType[frameworkInfo[start].r_type];
- *name = frameworkInfo[start].name;
- }
- }
- }
-}
+struct library_info library_infos[MAXINDEX];
+int num_libraries = 0;
+#define TEXT_R 0
+#define DATA_R 1
+#define OBJC_R 2
+#define IMPORT_R 3
+#define UNICODE_R 4
+#define IMAGE_R 5
+#define LINKEDIT_R 6
-/*
- * Comparison routines for sorting
- */
-static int compareFrameworkAddress(const void *aa, const void *bb)
+static void
+sort_library_addresses(void)
{
- LibraryInfo *a = (LibraryInfo *)aa;
- LibraryInfo *b = (LibraryInfo *)bb;
-
- if (a->b_address < b->b_address) return -1;
- if (a->b_address == b->b_address) return 0;
- return 1;
+ library_infos[num_libraries].b_address = library_infos[num_libraries - 1].b_address + 0x800000;
+ library_infos[num_libraries].e_address = library_infos[num_libraries].b_address;
+ library_infos[num_libraries].name = NULL;
+
+ qsort_b(library_infos, num_libraries, sizeof (struct library_info), ^int(const void *aa, const void *bb) {
+ struct library_info *a = (struct library_info *)aa;
+ struct library_info *b = (struct library_info *)bb;
+
+ if (a->b_address < b->b_address) return -1;
+ if (a->b_address == b->b_address) return 0;
+ return 1;
+ });
}
-
-int scanline(char *inputstring, char **argv, int maxtokens)
+static int
+scanline(char *inputstring, char **argv, int maxtokens)
{
int n = 0;
char **ap = argv, *p, *val;
for (p = inputstring; n < maxtokens && p != NULL; ) {
-
- while ((val = strsep(&p, " \t")) != NULL && *val == '\0');
+ while ((val = strsep(&p, " \t")) != NULL && *val == '\0') ;
*ap++ = val;
n++;
}
+
*ap = 0;
return n;
}
-
-int ReadSharedCacheMap(const char *path, LibraryRange *lr, char *linkedit_name)
+static int
+read_shared_cache_map(const char *path, struct library_range *lr, char *linkedit_name)
{
uint64_t b_address, e_address;
char buf[1024];
- char *fnp;
+ char *fnp, *fn_tofree;
FILE *fd;
char frameworkName[256];
char *tokens[64];
if (strncmp(buf, "mapping", 7))
break;
}
+
buf[strlen(buf)-1] = 0;
-
+
frameworkName[0] = 0;
for (;;) {
/*
* Extract lib name from path name
*/
- if ((substring = strrchr(buf, '.')))
- {
+ if ((substring = strrchr(buf, '.'))) {
/*
- * There is a ".": name is whatever is between the "/" around the "."
+ * There is a ".": name is whatever is between the "/" around the "."
*/
while ( *substring != '/') /* find "/" before "." */
substring--;
+
substring++;
strncpy(frameworkName, substring, 256); /* copy path from "/" */
while ( *substring != '/' && *substring) /* find "/" after "." and stop string there */
substring++;
+
*substring = 0;
- }
- else
- {
+ } else {
/*
* No ".": take segment after last "/"
*/
substring = ptr + 1;
ptr++;
}
+
strncpy(frameworkName, substring, 256);
frameworkName[255] = 0;
}
- fnp = (char *)malloc(strlen(frameworkName) + 1);
+
+ fnp = malloc(strlen(frameworkName) + 1);
+ fn_tofree = fnp;
strcpy(fnp, frameworkName);
- while (fgets(buf, 1023, fd) && numFrameworks < (MAXINDEX - 2)) {
+ while (fgets(buf, 1023, fd) && num_libraries < (MAXINDEX - 2)) {
/*
* Get rid of EOL
*/
b_address = strtoull(tokens[1], 0, 16);
e_address = strtoull(tokens[3], 0, 16);
- frameworkInfo[numFrameworks].b_address = b_address;
- frameworkInfo[numFrameworks].e_address = e_address;
- frameworkInfo[numFrameworks].r_type = type;
-
+ library_infos[num_libraries].b_address = b_address;
+ library_infos[num_libraries].e_address = e_address;
+ library_infos[num_libraries].r_type = type;
+
if (type == LINKEDIT_R) {
- frameworkInfo[numFrameworks].name = linkedit_name;
+ library_infos[num_libraries].name = linkedit_name;
linkedit_found = 1;
- } else
- frameworkInfo[numFrameworks].name = fnp;
+ } else {
+ library_infos[num_libraries].name = fnp;
+ fn_tofree = NULL;
+ }
#if 0
printf("%s(%d): %qx-%qx\n", frameworkInfo[numFrameworks].name, type, b_address, e_address);
#endif
if (lr->e_address == 0 || e_address > lr->e_address)
lr->e_address = e_address;
- numFrameworks++;
+ num_libraries++;
}
+
if (type == LINKEDIT_R)
break;
}
+
+ free(fn_tofree);
+
if (fgets(buf, 1023, fd) == 0)
break;
buf[strlen(buf)-1] = 0;
}
+
fclose(fd);
#if 0
return 1;
}
+void
+init_shared_cache_mapping(void)
+{
+ read_shared_cache_map("/var/db/dyld/dyld_shared_cache_i386.map", &framework32, "/var/db/dyld/dyld_shared_cache_i386");
+
+ if (0 == read_shared_cache_map("/var/db/dyld/dyld_shared_cache_x86_64h.map", &framework64h, "/var/db/dyld/dyld_shared_cache_x86_64h")) {
+ read_shared_cache_map("/var/db/dyld/dyld_shared_cache_x86_64.map", &framework64, "/var/db/dyld/dyld_shared_cache_x86_64");
+ }
+
+ sort_library_addresses();
+}
void
-SortFrameworkAddresses()
+lookup_name(uint64_t user_addr, char **type, char **name)
{
+ int i;
+ int start, last;
+
+ static char *frameworkType[] = {
+ "<TEXT> ",
+ "<DATA> ",
+ "<OBJC> ",
+ "<IMPORT> ",
+ "<UNICODE> ",
+ "<IMAGE> ",
+ "<LINKEDIT>",
+ };
+
+ *name = NULL;
+ *type = NULL;
+
+ if (num_libraries) {
+ if ((user_addr >= framework32.b_address && user_addr < framework32.e_address) ||
+ (user_addr >= framework64.b_address && user_addr < framework64.e_address) ||
+ (user_addr >= framework64h.b_address && user_addr < framework64h.e_address)) {
- frameworkInfo[numFrameworks].b_address = frameworkInfo[numFrameworks - 1].b_address + 0x800000;
- frameworkInfo[numFrameworks].e_address = frameworkInfo[numFrameworks].b_address;
- frameworkInfo[numFrameworks].name = (char *)0;
+ start = 0;
+ last = num_libraries;
+
+ for (i = num_libraries / 2; start < last; i = start + ((last - start) / 2)) {
+ if (user_addr > library_infos[i].e_address)
+ start = i+1;
+ else
+ last = i;
+ }
- qsort(frameworkInfo, numFrameworks, sizeof(LibraryInfo), compareFrameworkAddress);
+ if (start < num_libraries &&
+ user_addr >= library_infos[start].b_address && user_addr < library_infos[start].e_address) {
+ *type = frameworkType[library_infos[start].r_type];
+ *name = library_infos[start].name;
+ }
+ }
+ }
}
+#pragma mark disk I/O tracking routines
+
+struct diskio *free_diskios = NULL;
+struct diskio *busy_diskios = NULL;
-struct diskio *insert_diskio(int type, int bp, int dev, int blkno, int io_size, uintptr_t thread, double curtime)
+struct diskio *
+diskio_start(uint64_t type, uint64_t bp, uint64_t dev,
+ uint64_t blkno, uint64_t iosize, ktrace_event_t event)
{
- struct diskio *dio;
- threadmap_t tme;
-
- if ((dio = free_diskios))
+ const char *command;
+ struct diskio *dio;
+
+ if ((dio = free_diskios)) {
free_diskios = dio->next;
- else {
- if ((dio = (struct diskio *)malloc(sizeof(struct diskio))) == NULL)
- return (NULL);
+ } else {
+ dio = malloc(sizeof (struct diskio));
}
+
dio->prev = NULL;
-
+
dio->type = type;
dio->bp = bp;
dio->dev = dev;
dio->blkno = blkno;
- dio->iosize = io_size;
- dio->issued_time = curtime;
- dio->issuing_thread = thread;
-
- if ((tme = find_map_entry(thread))) {
- strncpy(dio->issuing_command, tme->tm_command, MAXCOMLEN);
- dio->issuing_command[MAXCOMLEN-1] = '\0';
- } else
- strcpy(dio->issuing_command, "");
-
+ dio->iosize = iosize;
+ dio->issued_time = event->timestamp;
+ dio->issuing_thread = event->threadid;
+ dio->issuing_pid = ktrace_get_pid_for_thread(s, event->threadid);
+
+ dio->bc_info = 0x0;
+
+ command = ktrace_get_execname_for_thread(s, event->threadid);
+
+ if (!command)
+ command = "";
+
+ strncpy(dio->issuing_command, command, MAXCOMLEN);
+ dio->issuing_command[MAXCOMLEN] = '\0';
+
dio->next = busy_diskios;
+
if (dio->next)
dio->next->prev = dio;
+
busy_diskios = dio;
- return (dio);
+ return dio;
}
-
-struct diskio *complete_diskio(int bp, int io_errno, int resid, uintptr_t thread, double curtime)
+struct diskio *
+diskio_find(uint64_t bp)
{
struct diskio *dio;
-
- for (dio = busy_diskios; dio; dio = dio->next) {
- if (dio->bp == bp) {
- if (dio == busy_diskios) {
- if ((busy_diskios = dio->next))
- dio->next->prev = NULL;
- } else {
- if (dio->next)
- dio->next->prev = dio->prev;
- dio->prev->next = dio->next;
- }
- dio->iosize -= resid;
- dio->io_errno = io_errno;
- dio->completed_time = curtime;
- dio->completion_thread = thread;
-
- return (dio);
- }
+ for (dio = busy_diskios; dio; dio = dio->next) {
+ if (dio->bp == bp)
+ return dio;
}
- return ((struct diskio *)0);
+
+ return NULL;
}
+struct diskio *
+diskio_complete(uint64_t bp, uint64_t io_errno, uint64_t resid,
+ uint64_t thread, uint64_t curtime, struct timeval curtime_wall)
+{
+ struct diskio *dio;
+
+ if ((dio = diskio_find(bp)) == NULL) return NULL;
+
+ if (dio == busy_diskios) {
+ if ((busy_diskios = dio->next))
+ dio->next->prev = NULL;
+ } else {
+ if (dio->next)
+ dio->next->prev = dio->prev;
+ dio->prev->next = dio->next;
+ }
+
+ dio->iosize -= resid;
+ dio->io_errno = io_errno;
+ dio->completed_time = curtime;
+ dio->completed_walltime = curtime_wall;
+ dio->completion_thread = thread;
+
+ return dio;
+}
-void free_diskio(struct diskio *dio)
+void
+diskio_free(struct diskio *dio)
{
dio->next = free_diskios;
free_diskios = dio;
}
-
-void print_diskio(struct diskio *dio)
+void
+diskio_print(struct diskio *dio)
{
char *p = NULL;
int len = 0;
- int type;
+ uint64_t type;
int format = FMT_DISKIO;
char buf[64];
type = dio->type;
+ dio->is_meta = 0;
if ((type & P_CS_Class) == P_CS_Class) {
-
switch (type) {
-
- case P_CS_ReadChunk:
- p = " RdChunkCS";
- len = 13;
- format = FMT_DISKIO_CS;
- break;
- case P_CS_WriteChunk:
- p = " WrChunkCS";
- len = 13;
- format = FMT_DISKIO_CS;
- break;
- case P_CS_MetaRead:
- p = " RdMetaCS";
- len = 10;
- format = FMT_DISKIO_CS;
- break;
- case P_CS_MetaWrite:
- p = " WrMetaCS";
- len = 10;
- format = FMT_DISKIO_CS;
- break;
- case P_CS_TransformRead:
- p = " RdBgTfCS";
- len = 10;
- break;
- case P_CS_TransformWrite:
- p = " WrBgTfCS";
- len = 10;
- break;
- case P_CS_MigrationRead:
- p = " RdBgMigrCS";
- len = 12;
- break;
- case P_CS_MigrationWrite:
- p = " WrBgMigrCS";
- len = 12;
- break;
+ case P_CS_ReadChunk:
+ p = " RdChunkCS";
+ len = 13;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_WriteChunk:
+ p = " WrChunkCS";
+ len = 13;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_MetaRead:
+ p = " RdMetaCS";
+ len = 10;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_MetaWrite:
+ p = " WrMetaCS";
+ len = 10;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_TransformRead:
+ p = " RdBgTfCS";
+ len = 10;
+ break;
+ case P_CS_TransformWrite:
+ p = " WrBgTfCS";
+ len = 10;
+ break;
+ case P_CS_MigrationRead:
+ p = " RdBgMigrCS";
+ len = 12;
+ break;
+ case P_CS_MigrationWrite:
+ p = " WrBgMigrCS";
+ len = 12;
+ break;
+ default:
+ p = " CS";
+ len = 4;
+ break;
}
+
strncpy(buf, p, len);
} else {
-
switch (type & P_DISKIO_TYPE) {
-
- case P_RdMeta:
- p = " RdMeta";
- len = 8;
- break;
- case P_WrMeta:
- p = " WrMeta";
- len = 8;
- break;
- case P_RdData:
- p = " RdData";
- len = 8;
- break;
- case P_WrData:
- p = " WrData";
- len = 8;
- break;
- case P_PgIn:
- p = " PgIn";
- len = 6;
- break;
- case P_PgOut:
- p = " PgOut";
- len = 7;
- break;
- default:
- p = " ";
- len = 2;
- break;
+ case P_RdMeta:
+ dio->is_meta = 1;
+ p = " RdMeta";
+ len = 8;
+ break;
+ case P_WrMeta:
+ dio->is_meta = 1;
+ p = " WrMeta";
+ len = 8;
+ break;
+ case P_RdData:
+ p = " RdData";
+ len = 8;
+ break;
+ case P_WrData:
+ p = " WrData";
+ len = 8;
+ break;
+ case P_PgIn:
+ p = " PgIn";
+ len = 6;
+ break;
+ case P_PgOut:
+ p = " PgOut";
+ len = 7;
+ break;
+ default:
+ p = " ";
+ len = 2;
+ break;
}
+
strncpy(buf, p, len);
buf[len++] = '[';
-
+
if (type & P_DISKIO_ASYNC)
buf[len++] = 'A';
else
if (type & P_DISKIO_NOCACHE)
buf[len++] = 'N';
- if (type & P_DISKIO_THROTTLE)
+ int tier = (type & P_DISKIO_TIER_MASK) >> P_DISKIO_TIER_SHIFT;
+
+ if (tier > 0) {
buf[len++] = 'T';
- else if (type & P_DISKIO_PASSIVE)
+ if (tier > 0 && tier < 10)
+ buf[len++] = '0' + tier;
+
+ if (type & P_DISKIO_TIER_UPGRADE) {
+ buf[len++] = 'U';
+ }
+ }
+
+ if (type & P_DISKIO_PASSIVE)
buf[len++] = 'P';
buf[len++] = ']';
}
+
buf[len] = 0;
- if (check_filter_mode(NULL, type, 0, 0, buf))
- format_print(NULL, buf, dio->issuing_thread, type, 0, 0, 0, 0, format, dio->completed_time, dio->issued_time, 1, "", dio);
+ if (check_filter_mode(-1, NULL, type, 0, 0, buf)) {
+ const char *pathname = ktrace_get_path_for_vp(s, dio->vnodeid);
+ format_print(NULL, buf, NULL, type, format, dio->completed_time,
+ dio->issued_time, 1, pathname ? pathname : "", dio);
+ }
}
+#pragma mark disk name routines
+
+struct diskrec {
+ struct diskrec *next;
+ char *diskname;
+ int dev;
+};
+
+struct diskrec *disk_list = NULL;
-void cache_disk_names()
+void
+cache_disk_names(void)
{
struct stat st;
DIR *dirp = NULL;
struct dirent *dir;
struct diskrec *dnp;
-
if ((dirp = opendir("/dev")) == NULL)
return;
-
+
while ((dir = readdir(dirp)) != NULL) {
char nbuf[MAXPATHLEN];
-
+
if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
continue;
snprintf(nbuf, MAXPATHLEN, "%s/%s", "/dev", dir->d_name);
-
+
if (stat(nbuf, &st) < 0)
continue;
- if ((dnp = (struct diskrec *)malloc(sizeof(struct diskrec))) == NULL)
+ if ((dnp = malloc(sizeof(struct diskrec))) == NULL)
continue;
-
- if ((dnp->diskname = (char *)malloc(dir->d_namlen + 1)) == NULL) {
+
+ if ((dnp->diskname = malloc(dir->d_namlen + 1)) == NULL) {
free(dnp);
continue;
}
strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
dnp->diskname[dir->d_namlen] = 0;
dnp->dev = st.st_rdev;
-
+
dnp->next = disk_list;
disk_list = dnp;
}
- (void) closedir(dirp);
-}
+ closedir(dirp);
+}
-void recache_disk_names()
+static void
+recache_disk_names(void)
{
struct diskrec *dnp, *next_dnp;
free(dnp->diskname);
free(dnp);
}
- disk_list = NULL;
+ disk_list = NULL;
cache_disk_names();
}
-
-char *find_disk_name(int dev)
+char *
+find_disk_name(uint64_t dev)
{
struct diskrec *dnp;
int i;
-
+
if (dev == NFS_DEV)
return ("NFS");
-
+
if (dev == CS_DEV)
return ("CS");
-
+
for (i = 0; i < 2; i++) {
for (dnp = disk_list; dnp; dnp = dnp->next) {
if (dnp->dev == dev)
}
recache_disk_names();
}
- return ("NOTFOUND");
-}
-
-
-char *generate_cs_disk_name(int dev, char *s)
-{
- if (dev == -1)
- return ("UNKNOWN");
-
- sprintf(s, "disk%ds%d", (dev >> 16) & 0xffff, dev & 0xffff);
-
- return (s);
-}
-
-
-
-/*
- * ret = 1 means print the entry
- * ret = 0 means don't print the entry
- */
-int
-check_filter_mode(struct th_info * ti, int type, int error, int retval, char *sc_name)
-{
- int ret = 0;
- int network_fd_isset = 0;
- unsigned int fd;
-
- if (filter_mode == DEFAULT_DO_NOT_FILTER)
- return(1);
-
- if (sc_name[0] == 'C' && !strcmp (sc_name, "CACHE_HIT")) {
- if (filter_mode & CACHEHIT_FILTER)
- /* Do not print if cachehit filter is set */
- return(0);
- return(1);
- }
-
- if (filter_mode & EXEC_FILTER) {
- if (type == BSC_execve || type == BSC_posix_spawn)
- return(1);
- return(0);
- }
-
- if (filter_mode & PATHNAME_FILTER) {
- if (ti && ti->pathname[0])
- return(1);
- if (type == BSC_close || type == BSC_close_nocancel)
- return(1);
- return(0);
- }
-
- if ( !(filter_mode & (FILESYS_FILTER | NETWORK_FILTER)))
- return(1);
-
- if (ti == (struct th_info *)0) {
- if (filter_mode & FILESYS_FILTER)
- return(1);
- return(0);
- }
-
- switch (type) {
-
- case BSC_close:
- case BSC_close_nocancel:
- fd = ti->arg1;
- network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
-
- if (error == 0)
- fs_usage_fd_clear(ti->thread,fd);
-
- if (network_fd_isset) {
- if (filter_mode & NETWORK_FILTER)
- ret = 1;
- } else if (filter_mode & FILESYS_FILTER)
- ret = 1;
- break;
-
- case BSC_read:
- case BSC_write:
- case BSC_read_nocancel:
- case BSC_write_nocancel:
- /*
- * we don't care about error in these cases
- */
- fd = ti->arg1;
- network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
-
- if (network_fd_isset) {
- if (filter_mode & NETWORK_FILTER)
- ret = 1;
- } else if (filter_mode & FILESYS_FILTER)
- ret = 1;
- break;
-
- case BSC_accept:
- case BSC_accept_nocancel:
- case BSC_socket:
- fd = retval;
-
- if (error == 0)
- fs_usage_fd_set(ti->thread, fd);
- if (filter_mode & NETWORK_FILTER)
- ret = 1;
- break;
-
- case BSC_recvfrom:
- case BSC_sendto:
- case BSC_recvmsg:
- case BSC_sendmsg:
- case BSC_connect:
- case BSC_bind:
- case BSC_listen:
- case BSC_sendto_nocancel:
- case BSC_recvfrom_nocancel:
- case BSC_recvmsg_nocancel:
- case BSC_sendmsg_nocancel:
- case BSC_connect_nocancel:
- fd = ti->arg1;
-
- if (error == 0)
- fs_usage_fd_set(ti->thread, fd);
- if (filter_mode & NETWORK_FILTER)
- ret = 1;
- break;
-
- case BSC_select:
- case BSC_select_nocancel:
- case BSC_socketpair:
- /*
- * Cannot determine info about file descriptors
- */
- if (filter_mode & NETWORK_FILTER)
- ret = 1;
- break;
-
- case BSC_dup:
- case BSC_dup2:
- /*
- * We track these cases for fd state only
- */
- fd = ti->arg1;
- network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
-
- if (error == 0 && network_fd_isset) {
- /*
- * then we are duping a socket descriptor
- */
- fd = retval; /* the new fd */
- fs_usage_fd_set(ti->thread, fd);
- }
- break;
-
- default:
- if (filter_mode & FILESYS_FILTER)
- ret = 1;
- break;
- }
-
- return(ret);
-}
-
-/*
- * Allocate a buffer that is large enough to hold the maximum arguments
- * to execve(). This is used when getting the arguments to programs
- * when we see LaunchCFMApps. If this fails, it is not fatal, we will
- * simply not resolve the command name.
- */
-
-void
-init_arguments_buffer()
-{
- int mib[2];
- size_t size;
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_ARGMAX;
- size = sizeof(argmax);
- if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
- return;
-#if 1
- /* Hack to avoid kernel bug. */
- if (argmax > 8192) {
- argmax = 8192;
- }
-#endif
- arguments = (char *)malloc(argmax);
+ return "NOTFOUND";
}
-
-int
-get_real_command_name(int pid, char *cbuf, int csize)
+char *
+generate_cs_disk_name(uint64_t dev, char *s)
{
- /*
- * Get command and arguments.
- */
- char *cp;
- int mib[4];
- char *command_beg, *command, *command_end;
-
- if (cbuf == NULL)
- return(0);
-
- if (arguments)
- bzero(arguments, argmax);
- else
- return(0);
-
- /*
- * A sysctl() is made to find out the full path that the command
- * was called with.
- */
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROCARGS2;
- mib[2] = pid;
- mib[3] = 0;
-
- if (sysctl(mib, 3, arguments, (size_t *)&argmax, NULL, 0) < 0)
- return(0);
-
- /*
- * Skip the saved exec_path
- */
- for (cp = arguments; cp < &arguments[argmax]; cp++) {
- if (*cp == '\0') {
- /*
- * End of exec_path reached
- */
- break;
- }
- }
- if (cp == &arguments[argmax])
- return(0);
-
- /*
- * Skip trailing '\0' characters
- */
- for (; cp < &arguments[argmax]; cp++) {
- if (*cp != '\0') {
- /*
- * Beginning of first argument reached
- */
- break;
- }
- }
- if (cp == &arguments[argmax])
- return(0);
-
- command_beg = cp;
- /*
- * Make sure that the command is '\0'-terminated. This protects
- * against malicious programs; under normal operation this never
- * ends up being a problem..
- */
- for (; cp < &arguments[argmax]; cp++) {
- if (*cp == '\0') {
- /*
- * End of first argument reached
- */
- break;
- }
- }
- if (cp == &arguments[argmax])
- return(0);
-
- command_end = command = cp;
+ if (dev == -1)
+ return "UNKNOWN";
- /*
- * Get the basename of command
- */
- for (command--; command >= command_beg; command--) {
- if (*command == '/') {
- command++;
- break;
- }
- }
- (void) strncpy(cbuf, (char *)command, csize);
- cbuf[csize-1] = '\0';
+ sprintf(s, "disk%" PRIu64 "s%" PRIu64, (dev >> 16) & 0xffff, dev & 0xffff);
- return(1);
+ return (s);
}