├── .gitignore ├── README.md ├── adm ├── createuser ├── mksmartvm └── rc.server ├── ios ├── simapp ├── simulator.gdb └── splashsnoop.d ├── launchd └── insecure.shell.plist ├── lib ├── binscale.py └── dcov.pl ├── lldb-run.py ├── objc ├── dtrace_objc.h ├── notificationhook │ ├── Makefile │ ├── hook.lldb │ ├── notification.provider.d │ └── notificationhook.m ├── nsnotifications.d └── test │ └── ui.clj ├── sys ├── acceptsnoop.d ├── connectsnoop.d ├── dispatch_trace.d ├── execsnoop.real.d ├── exectime.d ├── machportdump.c ├── machtrace.d ├── portsnoop.d ├── sockets.d └── waittrace.d └── xnu └── kdebug.gdb /.gitignore: -------------------------------------------------------------------------------- 1 | *.provider.h 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | darwinkit 2 | ========= 3 | 4 | Darwin scripts toolbox: DTrace and GDB scripts, housekeeping. 5 | See [lxperf](https://github.com/proger/lxperf) for Linux. 6 | 7 | ## OSX DTrace gotchas 8 | 9 | * there is no `progenyof` -- `mach_trace.d` has to track its children manually 10 | * unordered events due to DTrace having per-cpu buffers and threads migrating between cores; 11 | * OSX has no core affinity API 12 | * no `-x temporal` too ([what is temporal](https://github.com/illumos/illumos-gate/commit/e5803b76927480e8f9b67b22201c484ccf4c2bcf)) 13 | * workaround for `machtrace.d`: 14 | 15 | # column 2 should print the elapsed execution time 16 | dtrace -x evaltime=exec -Cs sys/machtrace.d -c ./a.out | sort -n -k2 17 | 18 | ## launchd stuff 19 | 20 | * [insecure.shell](launchd/insecure.shell.plist) -- helps you learn how screwed your launchd daemon/agent environment is 21 | * run client: `socat tcp-connect:localhost:12345 readline` 22 | * make sure you have `socat` installed at `/usr/local/bin`! (use homebrew) 23 | -------------------------------------------------------------------------------- /adm/createuser: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ -z "$1" || -z "$2" ]]; then 3 | echo "Usage: $0 username homedir_path" 4 | exit 1 5 | fi 6 | 7 | set -x 8 | 9 | NAME=$1 10 | HOME=$2 11 | next_uid=$((`dscl . ls /Users uid | awk '{print $2}' | sort -nr | head -n1` + 1)) 12 | next_gid=$((`dscl . ls /Groups gid | awk '{print $2}' | sort -nr | head -n1` + 1)) 13 | echo "create user group" 14 | dscl . -create /Groups/${NAME} 15 | dscl . -create /Groups/${NAME} PrimaryGroupID $next_gid 16 | echo "create user" 17 | dscl . -create /Users/${NAME} 18 | dscl . -create /Users/${NAME} UserShell /bin/bash 19 | dscl . -create /Users/${NAME} RealName "${NAME}" 20 | dscl . -create /Users/${NAME} UniqueID $next_uid 21 | dscl . -create /Users/${NAME} PrimaryGroupID $next_gid 22 | dscl . -create /Users/${NAME} NFSHomeDirectory "${HOME}" 23 | echo "assign user to his group" 24 | dscl . -append /Groups/${NAME} GroupMembership ${NAME} 25 | dscl . -append /Groups/com.apple.access_ssh GroupMembership ${NAME} 26 | dscl . -append /Groups/com.apple.access_screensharing GroupMembership ${NAME} 27 | dscl . -append /Groups/staff GroupMembership ${NAME} 28 | dscl . -append /Groups/wheel GroupMembership ${NAME} 29 | echo "create user home directory" 30 | mkdir -p ${HOME} 31 | chown ${NAME}:${NAME} ${HOME} 32 | 33 | # vim: set sw=4 sts=4 et tw=80 : 34 | -------------------------------------------------------------------------------- /adm/mksmartvm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # origin: https://github.com/jperkin/scripts 4 | # 5 | # Configurables: 6 | # 7 | # - Disk size is in GB 8 | # - Memory size is in MB 9 | # - SSH port is the local forwarded port to the VM:22 10 | # 11 | disksize="32" 12 | memsize="1024" 13 | sshport="8322" 14 | vmname="SmartOS" 15 | dlsite="https://download.joyent.com/pub/iso" 16 | 17 | vboxdir=$(VBoxManage list systemproperties \ 18 | | awk '/^Default.machine.folder/ { print $4 }') 19 | 20 | # 21 | # Download MD5 file and parse it for the latest ISO image and checksum 22 | # 23 | curl -o smartos-sums.txt ${dlsite}/md5sums.txt 2>/dev/null 24 | latest_md5=$(awk '/latest.iso/ { print $1 }' smartos-sums.txt) 25 | smartos_version=$(sed -ne "/^${latest_md5}/s/.*-\(.*\).iso/\1/p" \ 26 | smartos-sums.txt) 27 | if [ -z "${smartos_version}" ]; then 28 | echo "ERROR: Couldn't determine latest version" 29 | exit 1 30 | fi 31 | 32 | # 33 | # Download the latest ISO image and verify 34 | # 35 | mkdir -p "${vboxdir}/${vmname}" 36 | if [ ! -f "${vboxdir}/${vmname}/smartos-${smartos_version}.iso" ]; then 37 | echo "Downloading ${dlsite}/smartos-${smartos_version}.iso" 38 | curl -o "${vboxdir}/${vmname}/smartos-${smartos_version}.iso" \ 39 | ${dlsite}/smartos-${smartos_version}.iso 40 | #dl_md5=$(md5sum "${vboxdir}/${vmname}/smartos-${smartos_version}.iso" \ 41 | # | awk '{ print $1 }') 42 | dl_md5=$(md5 -q "${vboxdir}/${vmname}/smartos-${smartos_version}.iso") 43 | if [ -z "${dl_md5}" ]; then 44 | echo "ERROR: Couldn't fetch ISO image" 45 | exit 1 46 | fi 47 | if [ "${latest_md5}" != "${dl_md5}" ]; then 48 | echo "ERROR: md5 checksums do not match" 49 | exit 1 50 | fi 51 | fi 52 | 53 | # 54 | # Create VirtualBox VM 55 | # 56 | echo "Creating/Updating Virtual Machine" 57 | VBoxManage showvminfo "${vmname}" >/dev/null 2>&1 58 | if [ $? -eq 0 ]; then 59 | # VM already exists, just update the ISO image 60 | VBoxManage storageattach "${vmname}" --storagectl "IDE Controller" \ 61 | --port 1 --device 0 --type dvddrive \ 62 | --medium "${vboxdir}/${vmname}/smartos-${smartos_version}.iso" 63 | else 64 | # Create the VM 65 | VBoxManage createvm --name "${vmname}" --ostype OpenSolaris_64 --register 66 | VBoxManage storagectl "${vmname}" --name "IDE Controller" --add ide 67 | 68 | # Attach the ISO image 69 | VBoxManage storageattach "${vmname}" --storagectl "IDE Controller" \ 70 | --port 1 --device 0 --type dvddrive \ 71 | --medium "${vboxdir}/${vmname}/smartos-${smartos_version}.iso" 72 | 73 | # Create and attach the zone disk 74 | VBoxManage createhd --filename "${vboxdir}/${vmname}/smartos-zones.vdi" \ 75 | --size $(echo "${disksize}*1024" | bc) 76 | VBoxManage storageattach "${vmname}" --storagectl "IDE Controller" \ 77 | --port 0 --device 0 --type hdd \ 78 | --medium "${vboxdir}/${vmname}/smartos-zones.vdi" 79 | 80 | # Set misc settings 81 | VBoxManage modifyvm "${vmname}" --boot1 dvd --boot2 disk --boot3 none 82 | VBoxManage modifyvm "${vmname}" --memory ${memsize} 83 | VBoxManage modifyvm "${vmname}" --natpf1 "SSH,tcp,,${sshport},,22" 84 | fi 85 | 86 | # 87 | # Start it up 88 | # 89 | echo "Starting Virtual Machine" 90 | VirtualBox --startvm "${vmname}" & 91 | -------------------------------------------------------------------------------- /adm/rc.server: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # rc.server: server-specific boot initializations 4 | # 5 | # Copyright 2006-2009 Apple Inc and Darkproger. All rights reserved. 6 | # 7 | 8 | set -x 9 | echo HOLY FUCKING SHIT THIS IS /etc/rc.server ! 10 | /bin/ps axuww 11 | echo will start syslog early 12 | /usr/sbin/syslogd -D 13 | /bin/launchctl log level info 14 | echo will badaboom 15 | (cd /System/Library/LaunchDaemons; /bin/launchctl load *) 16 | 17 | #exec /bin/bash 18 | 19 | # 20 | # If you wish to override these or any other sysctl settings, copy 21 | # /etc/sysctl.conf.default to /etc/sysctl.conf and put your settings there; 22 | # it will be processed after this script. 23 | # 24 | # Refer to the man pages for launchctl(8) and sysctl(8) as well as 25 | # /etc/sysctl.conf.default for additional information. 26 | # 27 | 28 | PATH=/bin:/sbin:/usr/sbin:/usr/bin 29 | # 30 | # Set ipfw to configured state 31 | # 32 | if [ -f /etc/ipfilter/ipfw.conf.apple ]; then 33 | ipfw /etc/ipfilter/ipfw.conf.apple 34 | fi 35 | if [ -f /etc/ipfilter/ipfwstate-on ]; then 36 | sysctl -w net.inet.ip.fw.enable=1 37 | else 38 | sysctl -w net.inet.ip.fw.enable=0 39 | fi 40 | 41 | # 42 | # Set ip6fw to configured state 43 | # 44 | if [ -f /etc/ipfilter/ip6fw.conf.apple ]; then 45 | ip6fw /etc/ipfilter/ip6fw.conf.apple 46 | fi 47 | if [ -f /etc/ipfilter/ip6fwstate-on ]; then 48 | sysctl -w net.inet6.ip6.fw.enable=1 49 | else 50 | sysctl -w net.inet6.ip6.fw.enable=0 51 | fi 52 | 53 | # If we are not booted to tune our system as a server then just exit, perform no Tuning 54 | SERVER_INFO="/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/serverinfo"; 55 | if [ -e $SERVER_INFO ]; then 56 | if ! $SERVER_INFO -q --perfmode; then 57 | exit 58 | fi 59 | fi 60 | 61 | # 62 | # Set TCP to ack every other packet. (RFC-compliant "compatibility" mode.) 63 | # This should increase server performance, especially when connected 64 | # to Windows clients. 65 | # 66 | sysctl -w net.inet.tcp.delayed_ack=2 67 | 68 | # 69 | # Scale kernel parameters based on memory configuration. 70 | # 71 | (( memsize=$(sysctl -n hw.memsize) )) 72 | (( memsize/=1073741824 )) 73 | 74 | /bin/echo "rc.server[" $$ "]: Tuning server for ${memsize} GB (rounded down)." >> "/private/var/log/system.log" 75 | 76 | # Almost all tunings that had been done here are now done in the kernel, which should now use the ServerInformation framework rather than srv=1 77 | # 78 | # If you have a bunch of HFS+ filesystems, as we expect today on servers, then maxnbuf 79 | # still needs to grow slightly. This is especially true for file servers. 80 | # set -x 81 | if (( ${memsize} >= 2 )); then 82 | # Increase the system-wide limit on the number of processes. 83 | # Server requires a fair sized listen queue default 84 | sysctl -w kern.ipc.somaxconn=2500 85 | if [ `uname -m` == i386 ]; then 86 | # Always tune maxproc on K32 kernel 87 | sysctl -w kern.maxproc=2500 88 | # Increase the maximum number of open network sockets. 89 | # The kernel automatically scales these by available RAM to increase disk I/O 90 | # performance, but server generally wants more than the defaults. 91 | if (( ${memsize} >= 16 )); then 92 | sysctl -w kern.maxnbuf=60000 93 | sysctl -w kern.maxvnodes=280000 94 | sysctl -w kern.maxfiles=280000 95 | elif (( ${memsize} >= 8 )); then 96 | sysctl -w kern.maxnbuf=42000 97 | sysctl -w kern.maxvnodes=150000 98 | sysctl -w kern.maxfiles=150000 99 | elif (( ${memsize} >= 4 )); then 100 | sysctl -w kern.maxnbuf=21000 101 | sysctl -w kern.maxvnodes=120000 102 | sysctl -w kern.maxfiles=120000 103 | else 104 | sysctl -w kern.maxvnodes=90000 105 | sysctl -w kern.maxfiles=90000 106 | fi 107 | fi 108 | if [ `uname -m` == x86_64 ]; then 109 | # Even on K64, we do want a higher maxnbuf 110 | if (( ${memsize} >= 16 )); then 111 | sysctl -w kern.maxnbuf=160000 112 | # For sizes 16GB or greater, the kernel automatically scales 113 | # tuning paramaters to appropriate values for a server based 114 | # on installed memory size. The following commands can be used 115 | # to read the values on the running system: 116 | # sysctl kern.maxproc 117 | # sysctl kern.maxvnodes 118 | # sysctl kern.maxfiles 119 | elif ((${memsize} >= 8)); then 120 | # For sizes less than 16GB the kernel maxproc default isn't high enough 121 | sysctl -w kern.maxproc=2500 122 | sysctl -w kern.maxnbuf=60000 123 | sysctl -w kern.maxvnodes=150000 124 | sysctl -w kern.maxfiles=150000 125 | elif (( ${memsize} >= 4 )); then 126 | sysctl -w kern.maxproc=2500 127 | sysctl -w kern.maxnbuf=21000 128 | sysctl -w kern.maxvnodes=120000 129 | sysctl -w kern.maxfiles=120000 130 | else 131 | sysctl -w kern.maxproc=1500 132 | sysctl -w kern.maxvnodes=90000 133 | sysctl -w kern.maxfiles=90000 134 | fi 135 | fi 136 | fi 137 | 138 | # 139 | # Increase the number of processes each user may launch. 140 | # This must be done AFTER setting maxproc, because sysctl fails if a new 141 | # value exceeds its limit (instead of pegging to max). 142 | # The launchctl(8) command is necessary to raise the resource limit for 143 | # launchd(8) and its children. See getrlimit(2) for information. 144 | # 145 | (( maxproc=$(sysctl -n kern.maxproc) )) 146 | (( bigbunch = ${maxproc}/4 )) 147 | (( maxprocperuid=(${maxproc}>2500)?${bigbunch}:(${maxproc}-100) )) 148 | sysctl -w kern.maxprocperuid=${maxprocperuid} 149 | # 150 | # XXX This requires the filesystem to be mounted read-write to communicate 151 | # with launchd correctly. 152 | launchctl limit maxproc ${maxprocperuid} ${maxproc} 153 | 154 | # re-read the sysctl.conf file, so any overrides get re-applied 155 | if [ -f /etc/sysctl.conf ]; then 156 | while read cmd ignore; do 157 | case ${cmd} in 158 | \#*|'') ;; 159 | *) sysctl -w "${cmd}" ;; 160 | esac 161 | done < /etc/sysctl.conf 162 | fi 163 | # Fix for issue 7022012 164 | -------------------------------------------------------------------------------- /ios/simapp: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | app=$1 4 | binary=$2 5 | 6 | SDKVER=5.0 7 | REALHOME=$HOME 8 | 9 | exec env "TMPDIR=$REALHOME/Library/Application Support/iPhone Simulator/$SDKVER/Applications/$app/tmp" \ 10 | "HOME=$REALHOME/Library/Application Support/iPhone Simulator/$SDKVER/Applications/$app" \ 11 | "DYLD_FALLBACK_FRAMEWORK_PATH=/System/Library/Frameworks" \ 12 | "DYLD_ROOT_PATH=/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$SDKVER.sdk" \ 13 | "IPHONE_SIMULATOR_ROOT=/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$SDKVER.sdk" \ 14 | "IPHONE_SIMULATOR_CLASS=N90" \ 15 | "IPHONE_SIMULATOR_DEVICE=iPhone" \ 16 | "MallocCorruptionAbort=0" \ 17 | "IPHONE_SIMULATOR_MEMORY_WARNINGS=/tmp/iPhoneSimulatorMemoryWarning" \ 18 | "COMMAND_MODE=unix2003" \ 19 | "IPHONE_SHARED_RESOURCES_DIRECTORY=$REALHOME/Library/Application Support/iPhone Simulator/$SDKVER" \ 20 | "IPHONE_SIMULATOR_VERSIONS=iPhone Simulator 272, iPhone OS $SDKVER (iPhone (Retina)/9A334)" \ 21 | "CFFIXED_USER_HOME=$REALHOME/Library/Application Support/iPhone Simulator/$SDKVER/Applications/$app" \ 22 | "DYLD_FALLBACK_LIBRARY_PATH=/usr/lib" \ 23 | "__CF_USER_TEXT_ENCODING=0x1F5:0:0" \ 24 | \ 25 | "$REALHOME/Library/Application Support/iPhone Simulator/$SDKVER/Applications/$app/$binary.app/$binary" 26 | -------------------------------------------------------------------------------- /ios/simulator.gdb: -------------------------------------------------------------------------------- 1 | set shlib-path-substitutions / /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/ 2 | define penv 3 | set $env = (char **)environ 4 | set $i = 0 5 | while $env[$i] != 0 6 | p $env[$i] 7 | set $i = $i+1 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /ios/splashsnoop.d: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/dtrace -s 2 | 3 | syscall::open:entry 4 | /execname == "SpringBoard" && strstr(copyinstr(arg0), "Default@2x.png") != 0/ 5 | { 6 | trace(copyinstr(arg0)); 7 | ustack(); 8 | stopped = pid; 9 | stop(); 10 | } 11 | 12 | END /stopped != 0/ { 13 | pidresume(stopped); 14 | } 15 | -------------------------------------------------------------------------------- /launchd/insecure.shell.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WorkingDirectory 6 | / 7 | Debug 8 | 9 | Label 10 | insecure.shell 11 | OnDemand 12 | 13 | KeepAlive 14 | 15 | ProgramArguments 16 | 17 | /usr/local/bin/socat 18 | tcp-listen:12345,reuseaddr,bind=127.0.0.1 19 | exec:/bin/zsh,stderr 20 | 21 | RunAtLoad 22 | 23 | UserName 24 | proger 25 | 26 | EnvironmentVariables 27 | 28 | JAVA_HOME 29 | /Library/Java/JavaVirtualMachines/jdk1.7.0_13.jdk/Contents/Home 30 | PATH 31 | /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Server.app/Contents/ServerRoot/usr/bin:/Applications/Server.app/Contents/ServerRoot/usr/sbin:/tank/proger/local/bin:/tank/proger/local/ruby/bin 32 | GEM_HOME 33 | /tank/proger/local/ruby 34 | LC_CTYPE 35 | en_US.UTF-8 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /lib/binscale.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from random import choice 3 | 4 | COL_NORMAL = '\033[0m' 5 | COL_RED = '\033[1;31m' 6 | COL_GREEN = '\033[1;32m' 7 | COL_YELLOW = '\033[1;33m' 8 | COL_BLUE = '\033[1;34m' 9 | COL_WHITE = '\033[1;37m' 10 | COL_CYAN = '\033[1;36m' 11 | COL_GREY = '\033[1;30m' 12 | cols = [COL_RED, COL_GREEN, COL_YELLOW, COL_BLUE, COL_WHITE, COL_CYAN] 13 | 14 | def color(): 15 | c = cols.pop() 16 | cols.insert(0, c) 17 | return c 18 | 19 | def isbit(ch): 20 | return (ch in ['1', '0']) 21 | 22 | BIT_SEPARATOR = ' ' 23 | 24 | class bits(): 25 | ''' 26 | Class, which represents an int value in a bit string. 27 | ''' 28 | def __init__(self, n, nbits=8, descr=''): 29 | self.bit = (n, nbits) 30 | self.descr = descr 31 | 32 | def nbits(self): 33 | return self.bit[1] 34 | 35 | def val(self): 36 | return self.bit[0] 37 | 38 | def sign(self): 39 | ''' 40 | returns value description 41 | ''' 42 | return self.sign 43 | 44 | def ruler(self): 45 | ''' 46 | returns a ruler for bit string representation 47 | ''' 48 | return '|' + ''.join(['-' for i in range((self.nbits() - 1) * len(BIT_SEPARATOR) + self.nbits())]) + '|' 49 | 50 | def __str__(self): 51 | ''' 52 | returns bit string representation, each bit is separated by BIT_SEPARATOR, 53 | string is prefixed and suffixed by one space. 54 | ''' 55 | return ' ' + BIT_SEPARATOR.join([str((self.val() >> n) & 1) for n in range(self.nbits())][::-1]) + ' ' 56 | 57 | def __repr__(self): 58 | return str(self.bit) 59 | 60 | class bitfield(): 61 | BIT_OFFSET_MARK = 4 # mark offset every OFFSET_MARK bits 62 | MAX_OFFSET_LEN = 2 # max number of digits in offset 63 | 64 | ints = [] # Bitfields list, must be bit() instance 65 | width = 16 # Bits per string 66 | endianness = 'l' # only little endian for now, TODO: add support for more 67 | 68 | def __init__(self, *args, **kwargs): 69 | self.ints = list() 70 | 71 | for arg in list(args): 72 | if arg.__class__ == int: 73 | self.ints.append(bits(arg)) 74 | 75 | elif arg.__class__ == tuple and len(arg) == 2: 76 | self.ints.append(bits(arg[0], arg[1])) 77 | 78 | elif arg.__class__ == bits: 79 | self.ints.append(arg) 80 | 81 | if kwargs.get('reverse', None) != None: 82 | self.reverse() 83 | 84 | if kwargs.get('width', None) != None: 85 | self.width = kwargs.get('width', 16) 86 | 87 | def reverse(self): 88 | self.ints = self.ints[::-1] 89 | 90 | def bitstr(self): 91 | res = '\n' 92 | 93 | # create bit offset marks for every BIT_OFFSET_MARK bits 94 | bit_offset_marks = [] 95 | # for every bit string 96 | for n in range(self.nbits_total(), 0, -self.width): # little endian order 97 | marks = ' ' 98 | # for every mark 99 | for i in range(0, self.width, self.BIT_OFFSET_MARK): 100 | # add offsets 101 | for sp in range(0, len(BIT_SEPARATOR) * (self.BIT_OFFSET_MARK - 1) + self.BIT_OFFSET_MARK): 102 | marks += ' ' 103 | 104 | nmark = n - i - self.BIT_OFFSET_MARK 105 | if nmark < 0: break 106 | mark = str(nmark) 107 | while len(mark) < self.MAX_OFFSET_LEN: mark = '0' + mark 108 | marks += mark 109 | 110 | bit_offset_marks.append(marks) 111 | 112 | # pass one: concatenate components 113 | s = ''.join([str(i) for i in self.ints]) 114 | 115 | # pass two: leave only `width` bits on one line, 116 | # add space for offset marks 117 | npbits = 0 118 | ns = '' 119 | cbitcnt = 0 120 | intidx = 0 121 | ccol = color() 122 | for ch in s: 123 | if isbit(ch): 124 | if cbitcnt >= (self.ints[intidx].nbits() - 1): 125 | cbitcnt = 0 126 | intidx += 1 127 | ccol = color() 128 | else: 129 | ns += ccol 130 | cbitcnt += 1 131 | 132 | if npbits and (npbits % self.width) == 0: 133 | ns += '\n ' + ccol 134 | npbits += 1 135 | ns += ch 136 | else: 137 | ns += ch 138 | 139 | bitlist = ns.splitlines() 140 | 141 | for i in range(len(bitlist)): 142 | res += COL_GREY + bit_offset_marks[i] + '\n' 143 | res += bitlist[i] + '\n' 144 | 145 | return res 146 | 147 | def __repr__(self): 148 | return self.bitstr() 149 | 150 | def __str__(self): 151 | return self.bitstr() 152 | 153 | def nbits_total(self): 154 | n = 0 155 | for i in self.ints: n += i.nbits() 156 | return n 157 | 158 | @classmethod 159 | def byte(cls, bit): 160 | return bit / 8 161 | -------------------------------------------------------------------------------- /lib/dcov.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use Term::ANSIColor qw(:constants); 3 | 4 | $command = $ARGV[0]; 5 | $args = join ' ', @ARGV; 6 | 7 | `rm -f dtrace.out`; 8 | print `dtrace -q -n 'pid\$target::main: {printf("%s\\n",probename)}' -c "$args" -o dtrace.out`; 9 | @matches = `cat dtrace.out`; 10 | 11 | @fundump = `otool -tvV $command -p _main`; 12 | 13 | $base = undef; 14 | 15 | foreach $line (@fundump) { 16 | @parts = split /\s/, $line; 17 | next if $#parts < 2; 18 | 19 | 20 | $addr = hex $parts[0]; 21 | $base = $addr if $base == undef; 22 | 23 | $match = 0; 24 | foreach (@matches) { 25 | next if /^$/; 26 | next if /(entry|return)/; 27 | $match = 1 if ($addr - $base) == hex; 28 | } continue { 29 | last if $match; 30 | } 31 | 32 | print GREEN if $match; 33 | print $line; 34 | print RESET; 35 | } 36 | -------------------------------------------------------------------------------- /lldb-run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # lldb-run: because lldb -s is broken 4 | 5 | import sys 6 | sys.path.insert(0, '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 7 | 8 | import os 9 | from itertools import ifilter 10 | import jinja2 11 | 12 | pid = int(sys.argv[1]) 13 | 14 | import lldb 15 | 16 | dbg = lldb.SBDebugger.Create() 17 | dbg.SetAsync(False) 18 | 19 | target = dbg.CreateTarget(None) 20 | 21 | ci = dbg.GetCommandInterpreter() 22 | cro = lldb.SBCommandReturnObject() 23 | 24 | if pid > 0: 25 | listener = lldb.SBListener() 26 | errp = lldb.SBError() 27 | process = target.AttachToProcessWithID(listener, pid, errp) 28 | 29 | sys.stderr.write('attach: {}\n'.format(errp)) 30 | 31 | for command in ifilter(None, (l.strip() for l in sys.stdin.readlines())): 32 | comm = str(jinja2.Template(command).render(**os.environ)) 33 | 34 | if pid > 0: 35 | ci.HandleCommand(comm, cro) 36 | sys.stderr.write('{}: <{}>\n'.format(comm, cro)) 37 | else: 38 | sys.stderr.write('{}\n'.format(comm)) 39 | 40 | sys.exit(0) 41 | -------------------------------------------------------------------------------- /objc/dtrace_objc.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * XXX: this works only with compile-time CFStrings 4 | * hitting other types of CFStrings will produce user faults 5 | */ 6 | #define cfstring(p) copyinstr(*(user_addr_t *)copyin(p + 2*sizeof(user_addr_t), sizeof(user_addr_t))) 7 | -------------------------------------------------------------------------------- /objc/notificationhook/Makefile: -------------------------------------------------------------------------------- 1 | HOOK= notificationhook 2 | PROVIDER= notification.provider 3 | 4 | $(HOOK).dylib: $(HOOK).m $(PROVIDER).h 5 | clang -framework Foundation -shared -flat_namespace $< -o $@ 6 | 7 | $(PROVIDER).h: $(PROVIDER).d 8 | dtrace -h -s $< 9 | 10 | clean: 11 | rm -f $(HOOK).dylib $(PROVIDER).h 12 | 13 | apply: 14 | @test "$(PID)" -ge 1 2>/dev/null || (echo error: specify PID=; false) 15 | cat hook.lldb | python ../../lldb-run.py $(PID) 16 | sudo dtrace -m $(HOOK).dylib -l 17 | 18 | .PHONY: clean 19 | -------------------------------------------------------------------------------- /objc/notificationhook/hook.lldb: -------------------------------------------------------------------------------- 1 | expr (void*)dlopen("{{ PWD }}/notificationhook.dylib", 0x2|0x8) 2 | expr (void)notificationhook_do() 3 | -------------------------------------------------------------------------------- /objc/notificationhook/notification.provider.d: -------------------------------------------------------------------------------- 1 | provider NSNotificationCenter { 2 | probe notification__post(const char *); 3 | }; 4 | -------------------------------------------------------------------------------- /objc/notificationhook/notificationhook.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #include "notification.provider.h" 5 | 6 | static IMP original_NSNotificationCenter$$postNotificationName$_object$_; 7 | 8 | void 9 | NSNotificationCenter$$postNotificationName$_object$_(id self, SEL _cmd, NSString *name, id object) 10 | { 11 | if (NSNOTIFICATIONCENTER_NOTIFICATION_POST_ENABLED()) { 12 | NSNOTIFICATIONCENTER_NOTIFICATION_POST([[name description] UTF8String]); 13 | } 14 | 15 | original_NSNotificationCenter$$postNotificationName$_object$_(self, _cmd, name, object); 16 | } 17 | 18 | void 19 | notificationhook_do(void) 20 | { 21 | Class class = objc_getClass("NSNotificationCenter"); 22 | SEL selector = sel_getUid("postNotificationName:object:"); 23 | 24 | Method method = class_getInstanceMethod(class, selector); 25 | original_NSNotificationCenter$$postNotificationName$_object$_ = method_getImplementation(method); 26 | method_setImplementation(method, (IMP)NSNotificationCenter$$postNotificationName$_object$_); 27 | } 28 | -------------------------------------------------------------------------------- /objc/nsnotifications.d: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/dtrace I. -Cs 2 | 3 | #include "dtrace_objc.h" 4 | 5 | #if 1 6 | objc$target::*postNotification*:entry 7 | { 8 | @[cfstring(arg2)] = count(); 9 | } 10 | 11 | tick-1s 12 | { 13 | printa(@); 14 | trunc(@); 15 | } 16 | 17 | #endif 18 | 19 | #if 0 20 | objc$target::*addObserver?selector?name?*:entry 21 | { 22 | printf("%d [%s %s] %s\n", tid, probemod, probefunc, cfstring(arg4)); 23 | ustack(); 24 | } 25 | 26 | objc$target::*postNotificationName?*:entry 27 | { 28 | printf("%d [%s %s] %s\n", tid, probemod, probefunc, cfstring(arg2)); 29 | ustack(); 30 | } 31 | 32 | objc$target:__CFNotification:*initWithName?*:entry 33 | { 34 | printf("%d [%s %s] %s\n", tid, probemod, probefunc, cfstring(arg2)); 35 | ustack(); 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /objc/test/ui.clj: -------------------------------------------------------------------------------- 1 | (import '[java.awt Component]) 2 | (import '[javax.swing JFrame JButton JOptionPane JTextArea BoxLayout]) 3 | (import '[java.awt.event ActionListener]) 4 | 5 | (let [frame (doto (JFrame. "Hello Swing") 6 | (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)) 7 | layout (BoxLayout. (.getContentPane frame) BoxLayout/Y_AXIS) 8 | textfield (doto (JTextArea. (slurp "ui.clj")) 9 | (.setEditable false)) 10 | button (doto (JButton. "Click Me") 11 | (.setAlignmentX Component/CENTER_ALIGNMENT) 12 | (.addActionListener 13 | (reify ActionListener 14 | (actionPerformed [this evt] 15 | (JOptionPane/showMessageDialog 16 | nil 17 | (str 18 | "Hello from Clojure. " 19 | "Button " (.getActionCommand evt) " clicked."))))))] 20 | 21 | (doto (.getContentPane frame) 22 | (.setLayout layout) 23 | (.add textfield) 24 | (.add button)) 25 | 26 | (doto frame 27 | .pack 28 | (.setLocationRelativeTo nil) 29 | (.setVisible true))) 30 | -------------------------------------------------------------------------------- /sys/acceptsnoop.d: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dtrace -s 2 | 3 | typedef struct sockaddr_in { 4 | short sin_family; 5 | unsigned short sin_port; 6 | unsigned char a0; 7 | unsigned char a1; 8 | unsigned char a2; 9 | unsigned char a3; 10 | } sockaddr_in_t; 11 | 12 | BEGIN 13 | { 14 | afd["", 0] = 0; 15 | } 16 | 17 | syscall::accept*:entry 18 | { 19 | self->sinaddr = arg1; 20 | } 21 | 22 | syscall::accept*:return 23 | { 24 | this->sin = (struct sockaddr_in *)copyin(self->sinaddr, sizeof(struct sockaddr_in)); 25 | printf("%s:%d -- %d.%d.%d.%d:%hu", execname, arg1, 26 | this->sin->a0, 27 | this->sin->a1, 28 | this->sin->a2, 29 | this->sin->a3, 30 | this->sin->sin_port); 31 | afd[execname, arg1] = 1; 32 | } 33 | 34 | syscall::close:entry 35 | /afd[execname, arg0] == 1/ 36 | { 37 | printf("%s:%d", execname, arg0); 38 | afd[execname, arg0] = 0; 39 | } 40 | -------------------------------------------------------------------------------- /sys/connectsnoop.d: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dtrace -Cs 2 | 3 | /* tested on darwin */ 4 | 5 | #define AF_INET 2 6 | 7 | typedef struct sockaddr_in { 8 | short sin_family; 9 | unsigned short sin_port; 10 | unsigned char a0; 11 | unsigned char a1; 12 | unsigned char a2; 13 | unsigned char a3; 14 | } sockaddr_in_t; 15 | 16 | syscall::connect:entry 17 | #ifdef EXECNAME 18 | /execname == EXECNAME/ 19 | #endif 20 | { 21 | this->sin = (struct sockaddr_in *)copyin(arg1, sizeof(struct sockaddr_in)); 22 | this->fd = arg0; 23 | trace("connect"); 24 | } 25 | 26 | syscall::connect:return 27 | /this->sin/ 28 | { 29 | printf("%s:%d -- %d.%d.%d.%d:%hu (ret=%d)", execname, this->fd, 30 | this->sin->a0, 31 | this->sin->a1, 32 | this->sin->a2, 33 | this->sin->a3, 34 | this->sin->sin_port, 35 | arg1); 36 | } 37 | -------------------------------------------------------------------------------- /sys/dispatch_trace.d: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/dtrace -Z -s 2 | 3 | /* 4 | * Copyright (c) 2010-2011 Apple Inc. All rights reserved. 5 | * Copyright (c) 2013 Vladimir Kirillov 6 | * 7 | * @APPLE_APACHE_LICENSE_HEADER_START@ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * @APPLE_APACHE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | /* 25 | * Usage: dispatch_dtrace.d -p [pid] 26 | * traced process must have been executed with 27 | * DYLD_IMAGE_SUFFIX=_profile or DYLD_IMAGE_SUFFIX=_debug 28 | * 29 | * _OR_ 30 | * 31 | * mv -v /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/usr/lib/system/libdispatch.dylib{,.backup} 32 | * cp -v /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/usr/lib/system/{introspection/,}libdispatch.dylib 33 | */ 34 | 35 | #pragma D option quiet 36 | #pragma D option bufsize=16m 37 | 38 | BEGIN { 39 | printf("%-8s %-3s %-8s %-35s%-15s%-?s %-43s%-?s %-14s%-?s %s\n", 40 | "Time us", "CPU", "Thread", "Function", "Probe", "Queue", "Label", 41 | "Item", "Kind", "Context", "Symbol"); 42 | } 43 | 44 | dispatch$target:::queue-push, 45 | dispatch$target:::queue-push, 46 | dispatch$target:::queue-pop, 47 | dispatch$target:::queue-pop, 48 | dispatch$target:::callout-entry, 49 | dispatch$target:::callout-entry, 50 | dispatch$target:::callout-return, 51 | dispatch$target:::callout-return /!start/ { 52 | start = walltimestamp; 53 | } 54 | 55 | /* probe queue-push/-pop(dispatch_queue_t queue, const char *label, 56 | * dispatch_object_t item, const char *kind, 57 | * dispatch_function_t function, void *context) 58 | */ 59 | dispatch$target:::queue-push, 60 | dispatch$target:::queue-push, 61 | dispatch$target:::queue-pop, 62 | dispatch$target:::queue-pop { 63 | printf("%-8d %-3d 0x%08p %-35s%-15s0x%0?p %-43s0x%0?p %-14s0x%0?p", 64 | (walltimestamp-start)/1000, cpu, tid, probefunc, probename, arg0, 65 | copyinstr(arg1, 42), arg2, copyinstr(arg3, 13), arg5); 66 | usym(arg4); 67 | printf("\n"); 68 | } 69 | 70 | /* probe callout-entry/-return(dispatch_queue_t queue, const char *label, 71 | * dispatch_function_t function, void *context) 72 | */ 73 | dispatch$target:::callout-entry, 74 | dispatch$target:::callout-entry, 75 | dispatch$target:::callout-return, 76 | dispatch$target:::callout-return { 77 | printf("%-8d %-3d 0x%08p %-35s%-15s0x%0?p %-43s%-?s %-14s0x%0?p", 78 | (walltimestamp-start)/1000, cpu, tid, probefunc, probename, arg0, 79 | copyinstr(arg1, 42), "", "", arg3); 80 | usym(arg2); 81 | printf("\n"); 82 | } 83 | -------------------------------------------------------------------------------- /sys/execsnoop.real.d: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/dtrace -Cs 2 | #pragma D option quiet 3 | 4 | fbt::__mac_execve:entry, fbt::posix_spawn:entry 5 | { 6 | self->want_malloc = 1; 7 | } 8 | 9 | /* 10 | * First _MALLOC call inside execve/posix_spawn allocates memory 11 | * for struct image_params, which will later be used to store 12 | * pointers to copied in argv vector. 13 | * 14 | * We can't get this pointer from any of exec_* functions because 15 | * they are static and not exposed to fbt in the vanilla kernel. 16 | */ 17 | 18 | fbt::_MALLOC:return 19 | /self->want_malloc == 1/ 20 | { 21 | self->imgp = (struct image_params *)arg1; 22 | self->want_malloc = 0; 23 | } 24 | 25 | /* 26 | * At this point we know that the ip_startargv and friends are 27 | * filled in. 28 | */ 29 | 30 | proc:::exec-success 31 | { 32 | this->arglen = self->imgp->ip_endargv - self->imgp->ip_startargv; 33 | this->arg = self->imgp->ip_startargv; 34 | printf("[%d->%d] ", ppid, pid); 35 | } 36 | 37 | #define ITER() \ 38 | proc:::exec-success \ 39 | /this->arglen > 0/ \ 40 | { \ 41 | printf("%s ", stringof(this->arg)); \ 42 | this->arglen -= strlen(stringof(this->arg)) + 1; \ 43 | this->arg += strlen(stringof(this->arg)) + 1; \ 44 | } 45 | 46 | ITER() 47 | ITER() 48 | ITER() 49 | ITER() 50 | ITER() 51 | ITER() 52 | ITER() 53 | ITER() 54 | ITER() 55 | ITER() 56 | ITER() 57 | 58 | proc:::exec-success 59 | { 60 | printf("\n"); 61 | } 62 | -------------------------------------------------------------------------------- /sys/exectime.d: -------------------------------------------------------------------------------- 1 | proc:::create 2 | { 3 | procs[pid] = timestamp; 4 | printf("%s pid %d ppid %d", execname, pid, ppid); 5 | } 6 | 7 | proc:::exec-success 8 | { 9 | printf("%s pid %d ppid %d creation: %d us", execname, pid, ppid, (timestamp - procs[ppid]) / 1000); 10 | } 11 | 12 | proc:::exit 13 | { 14 | printf("%s pid %d ppid %d lifetime: %d us", execname, pid, ppid, (timestamp - procs[ppid]) / 1000); 15 | } 16 | -------------------------------------------------------------------------------- /sys/machportdump.c: -------------------------------------------------------------------------------- 1 | /* 2 | File: MachPortDump.c 3 | 4 | Contains: A program to dump the Mach ports for a process. 5 | 6 | Written by: DTS 7 | 8 | Copyright: Copyright (c) 2004 by Apple Computer, Inc., All Rights Reserved. 9 | 10 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. 11 | ("Apple") in consideration of your agreement to the following terms, and your 12 | use, installation, modification or redistribution of this Apple software 13 | constitutes acceptance of these terms. If you do not agree with these terms, 14 | please do not use, install, modify or redistribute this Apple software. 15 | 16 | In consideration of your agreement to abide by the following terms, and subject 17 | to these terms, Apple grants you a personal, non-exclusive license, under Apple's 18 | copyrights in this original Apple software (the "Apple Software"), to use, 19 | reproduce, modify and redistribute the Apple Software, with or without 20 | modifications, in source and/or binary forms; provided that if you redistribute 21 | the Apple Software in its entirety and without modifications, you must retain 22 | this notice and the following text and disclaimers in all such redistributions of 23 | the Apple Software. Neither the name, trademarks, service marks or logos of 24 | Apple Computer, Inc. may be used to endorse or promote products derived from the 25 | Apple Software without specific prior written permission from Apple. Except as 26 | expressly stated in this notice, no other rights or licenses, express or implied, 27 | are granted by Apple herein, including but not limited to any patent rights that 28 | may be infringed by your derivative works or by other works in which the Apple 29 | Software may be incorporated. 30 | 31 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 32 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 33 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 35 | COMBINATION WITH YOUR PRODUCTS. 36 | 37 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 38 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 39 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 41 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT 42 | (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN 43 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Change History (most recent first): 46 | 47 | $Log: MachPortDump.c,v $ 48 | Revision 1.1 2004/11/01 14:47:10 eskimo1 49 | Initial revision 50 | 51 | 52 | */ 53 | 54 | ///////////////////////////////////////////////////////////////// 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | #include 65 | 66 | #include 67 | 68 | ///////////////////////////////////////////////////////////////// 69 | #pragma mark ***** Compatibility Note 70 | 71 | // Apple strongly recommends that developers avoid using Mach APIs 72 | // directly. Mach APIs represent the lowest-level interface to 73 | // the kernel, and thus they are the most likely to change (or 74 | // become unsupportable) as the kernel evolves. 75 | // 76 | // Apple strongly recommends that developers use high-level wrappers 77 | // around Mach APIs where possible. For example, rather than use 78 | // Mach messages directly, you could use CFMessagePort. You should 79 | // only use Mach APIs if there is no higher-level alternatively. 80 | // 81 | // This sample uses Mach APIs directly, and thus seems to contravene 82 | // the above recommendations. However, this is justified by the last 83 | // sentence of the previous paragraph: the job this sample does, 84 | // displaying information about a Mach task's port right name space, 85 | // is only possible via the use of Mach APIs. 86 | // 87 | // It might make sense for you to copy the techniques used by 88 | // MachPortDump into your application, to help detect port right 89 | // leaks and so on. However, I strongly recommend that you include 90 | // this code only in your debug build. 91 | 92 | ///////////////////////////////////////////////////////////////// 93 | #pragma mark ***** The Code 94 | 95 | static const char *gProgramName; 96 | 97 | static void PrintPortSetMembers(mach_port_t taskSendRight, mach_port_name_t portSetName) 98 | // For a given Mach port set within a given task, print the members 99 | // of the port set. 100 | { 101 | kern_return_t err; 102 | kern_return_t junk; 103 | mach_port_name_array_t memberNames; 104 | mach_msg_type_number_t memberNamesCount; 105 | mach_msg_type_number_t memberIndex; 106 | 107 | memberNames = NULL; 108 | 109 | // Get an array of members. 110 | 111 | err = mach_port_get_set_status( 112 | taskSendRight, 113 | portSetName, 114 | &memberNames, 115 | &memberNamesCount 116 | ); 117 | 118 | // Iterate over the array, printing each one. Note that we print 6 members to 119 | // a line and we start every line except the second with enough spaces to 120 | // account for the information that we print that's common to each type 121 | // of output. 122 | 123 | if (err == KERN_SUCCESS) { 124 | fprintf(stdout, " "); 125 | for (memberIndex = 0; memberIndex < memberNamesCount; memberIndex++) { 126 | if ( (memberIndex != 0) && (memberIndex % 6) == 0) { 127 | // 6 columns of (8 characters plus space) 128 | // plus DNR column (3 chars) plus space 129 | fprintf(stdout, "\n%*s ", (6 * (8 + 1)) + 3 + 1, ""); 130 | } 131 | fprintf(stdout, "%#8x ", memberNames[memberIndex]); 132 | } 133 | } else { 134 | fprintf(stdout, "??? "); 135 | } 136 | 137 | // Clean up. 138 | 139 | if (memberNames != NULL) { 140 | junk = vm_deallocate(mach_task_self(), (vm_address_t) memberNames, memberNamesCount * sizeof(*memberNames)); 141 | assert(junk == KERN_SUCCESS); 142 | } 143 | } 144 | 145 | static void PrintPortReceiveStatus(mach_port_t taskSendRight, mach_port_name_t receiveRight) 146 | // Print information about the Mach receive right in the specified 147 | // task. 148 | { 149 | kern_return_t err; 150 | mach_port_status_t status; 151 | mach_msg_type_number_t statusCount; 152 | 153 | // Get information about the the right. 154 | 155 | statusCount = MACH_PORT_RECEIVE_STATUS_COUNT; 156 | err = mach_port_get_attributes( 157 | taskSendRight, 158 | receiveRight, 159 | MACH_PORT_RECEIVE_STATUS, 160 | (mach_port_info_t) &status, 161 | &statusCount 162 | ); 163 | assert( (err != KERN_SUCCESS) || (statusCount == MACH_PORT_RECEIVE_STATUS_COUNT) ); 164 | 165 | // Print it, as a group of flags followed by 6 columns of numbers, 166 | // which are basically all counters. 167 | 168 | if (err == KERN_SUCCESS) { 169 | fprintf( 170 | stdout, 171 | "%c%c%c ", 172 | (status.mps_nsrequest ? 'N' : '-'), 173 | (status.mps_pdrequest ? 'P' : '-'), 174 | (status.mps_srights ? 'S' : '-') 175 | ); 176 | 177 | fprintf( 178 | stdout, 179 | "%8u %8u %8u %8u %8u %8u", 180 | status.mps_seqno, 181 | status.mps_mscount, 182 | status.mps_qlimit, 183 | status.mps_msgcount, 184 | status.mps_sorights, 185 | status.mps_pset 186 | ); 187 | // The kernel always sets mps_flags to 0, so we don't both printing it. 188 | assert(status.mps_flags == 0); 189 | } else { 190 | fprintf( 191 | stdout, 192 | "??? %8s %8s %8s %8s %8s %8s", 193 | "???", "???", "???", "???", "???", "???" 194 | ); 195 | } 196 | } 197 | 198 | static kern_return_t PrintProcessPortSpace(pid_t pid, bool verbose) 199 | // Prints port rights owned by the specified process. 200 | { 201 | kern_return_t err; 202 | kern_return_t junk; 203 | mach_port_t taskSendRight; 204 | mach_port_name_array_t rightNames; 205 | mach_msg_type_number_t rightNamesCount; 206 | mach_port_type_array_t rightTypes; 207 | mach_msg_type_number_t rightTypesCount; 208 | unsigned int i; 209 | 210 | taskSendRight = MACH_PORT_NULL; 211 | rightNames = NULL; 212 | rightTypes = NULL; 213 | 214 | // Get the task control port for the process. 215 | 216 | err = task_for_pid(mach_task_self(), pid, &taskSendRight); 217 | if (err != KERN_SUCCESS) { 218 | fprintf(stderr, "%s: Could not attach to process %lld (%#08x).\n", gProgramName, (long long) pid, err); 219 | } 220 | 221 | // Get a snapshot of the port name space for the task. 222 | 223 | if (err == KERN_SUCCESS) { 224 | err = mach_port_names(taskSendRight, &rightNames, &rightNamesCount, &rightTypes, &rightTypesCount); 225 | } 226 | if (err == KERN_SUCCESS) { 227 | if ( rightNamesCount != rightTypesCount ) { 228 | fprintf(stderr, "%s: Count mismatch (%u/%u)\n", gProgramName, rightNamesCount, rightTypesCount); 229 | err = KERN_FAILURE; 230 | } 231 | } 232 | 233 | // Print that snapshot. 234 | 235 | if (err == KERN_SUCCESS) { 236 | fprintf(stdout, " Name Send Receive SendOnce PortSet DeadName DNR"); 237 | if (verbose) { 238 | fprintf(stdout, " flg seqno mscount qlimit msgcount sorights pset"); 239 | } 240 | fprintf(stdout, "\n"); 241 | fprintf(stdout, " ---- ---- ------- -------- ------- -------- ---"); 242 | if (verbose) { 243 | fprintf(stdout, " --- ----- ------- ------ -------- -------- ----"); 244 | } 245 | fprintf(stdout, "\n"); 246 | 247 | // For each name, print a reference count of each type of right. If running 248 | // verbose, print other information as well. 249 | 250 | for (i = 0; i < rightNamesCount; i++) { 251 | mach_port_right_t right; 252 | 253 | // We print the right name in hex because it makes it easier to 254 | // see the index and generation fields. See for 255 | // information about this. 256 | 257 | fprintf(stdout, "%#8x ", rightNames[i]); 258 | 259 | for (right = MACH_PORT_RIGHT_SEND; right <= MACH_PORT_RIGHT_DEAD_NAME; right++) { 260 | mach_port_urefs_t refCount; 261 | 262 | // If the rightTypes for this name has the bit associated 263 | // with this type of right set (that is, if the name 264 | // references this type of right), get the name's reference 265 | // for this right and print it. Otherwise just print an 266 | // empty string to keep the columns lined up. 267 | 268 | if (rightTypes[i] & MACH_PORT_TYPE(right)) { 269 | 270 | err = mach_port_get_refs(taskSendRight, rightNames[i], right, &refCount); 271 | if (err == KERN_SUCCESS) { 272 | fprintf(stdout, "%8d ", refCount); 273 | } else { 274 | fprintf(stdout, "%8s ", "???"); 275 | } 276 | } else { 277 | fprintf(stdout, "%8s ", ""); 278 | } 279 | } 280 | if ( rightTypes[i] & MACH_PORT_TYPE_DNREQUEST ) { 281 | fprintf(stdout, "yes "); 282 | } else { 283 | fprintf(stdout, " "); 284 | } 285 | 286 | if (verbose) { 287 | if (rightTypes[i] & MACH_PORT_TYPE_PORT_SET) { 288 | PrintPortSetMembers(taskSendRight, rightNames[i]); 289 | } else if (rightTypes[i] & MACH_PORT_TYPE_RECEIVE) { 290 | PrintPortReceiveStatus(taskSendRight, rightNames[i]); 291 | } 292 | } 293 | fprintf(stdout, "\n"); 294 | } 295 | } 296 | 297 | // Clean up. 298 | 299 | if (rightNames != NULL) { 300 | junk = vm_deallocate(mach_task_self(), (vm_address_t) rightNames, rightNamesCount * sizeof(*rightNames)); 301 | assert(junk == KERN_SUCCESS); 302 | } 303 | if (rightTypes != NULL) { 304 | junk = vm_deallocate(mach_task_self(), (vm_address_t) rightTypes, rightTypesCount * sizeof(*rightTypes)); 305 | assert(junk == KERN_SUCCESS); 306 | } 307 | if (taskSendRight != MACH_PORT_NULL) { 308 | junk = mach_port_deallocate(mach_task_self(), taskSendRight); 309 | assert(junk == KERN_SUCCESS); 310 | } 311 | 312 | return err; 313 | } 314 | 315 | typedef struct kinfo_proc kinfo_proc; 316 | 317 | static int GetBSDProcessList(kinfo_proc **procList, size_t *procCount) 318 | // Returns a list of all BSD processes on the system. This routine 319 | // allocates the list and puts it in *procList and a count of the 320 | // number of entries in *procCount. You are responsible for freeing 321 | // this list (use "free" from System framework). 322 | // On success, the function returns 0. 323 | // On error, the function returns a BSD errno value. 324 | { 325 | int err; 326 | kinfo_proc * result; 327 | bool done; 328 | static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; 329 | // Declaring name as const requires us to cast it when passing it to 330 | // sysctl because the prototype doesn't include the const modifier. 331 | size_t length; 332 | 333 | assert( procList != NULL); 334 | assert(*procList == NULL); 335 | assert(procCount != NULL); 336 | 337 | *procCount = 0; 338 | 339 | // We start by calling sysctl with result == NULL and length == 0. 340 | // That will succeed, and set length to the appropriate length. 341 | // We then allocate a buffer of that size and call sysctl again 342 | // with that buffer. If that succeeds, we're done. If that fails 343 | // with ENOMEM, we have to throw away our buffer and loop. Note 344 | // that the loop causes use to call sysctl with NULL again; this 345 | // is necessary because the ENOMEM failure case sets length to 346 | // the amount of data returned, not the amount of data that 347 | // could have been returned. 348 | 349 | result = NULL; 350 | done = false; 351 | do { 352 | assert(result == NULL); 353 | 354 | // Call sysctl with a NULL buffer. 355 | 356 | length = 0; 357 | err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, 358 | NULL, &length, 359 | NULL, 0); 360 | if (err == -1) { 361 | err = errno; 362 | } 363 | 364 | // Allocate an appropriately sized buffer based on the results 365 | // from the previous call. 366 | 367 | if (err == 0) { 368 | result = malloc(length); 369 | if (result == NULL) { 370 | err = ENOMEM; 371 | } 372 | } 373 | 374 | // Call sysctl again with the new buffer. If we get an ENOMEM 375 | // error, toss away our buffer and start again. 376 | 377 | if (err == 0) { 378 | err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, 379 | result, &length, 380 | NULL, 0); 381 | if (err == -1) { 382 | err = errno; 383 | } 384 | if (err == 0) { 385 | done = true; 386 | } else if (err == ENOMEM) { 387 | assert(result != NULL); 388 | free(result); 389 | result = NULL; 390 | err = 0; 391 | } 392 | } 393 | } while (err == 0 && ! done); 394 | 395 | // Clean up and establish post conditions. 396 | 397 | if (err != 0 && result != NULL) { 398 | free(result); 399 | result = NULL; 400 | } 401 | *procList = result; 402 | if (err == 0) { 403 | *procCount = length / sizeof(kinfo_proc); 404 | } 405 | 406 | assert( (err == 0) == (*procList != NULL) ); 407 | 408 | return err; 409 | } 410 | 411 | static int FindProcessByName(const char *processName, pid_t *pid) 412 | // Find the process that best matches processName and return 413 | // its PID. It first tries to find an exact match; if that fails 414 | // it tries to find a substring match; if that fails it checks 415 | // whether processName is a number and returns that as the PID. 416 | // 417 | // On entry, processName must not be NULL, and it must not be the 418 | // empty string. pid must not be NULL. 419 | // On success, *pid will be the process ID of the found process. 420 | // On error, *pid is undefined. 421 | { 422 | int err; 423 | int foundCount; 424 | kinfo_proc * processList; 425 | size_t processCount; 426 | size_t processIndex; 427 | 428 | assert(processName != NULL); 429 | assert(processName[0] != 0); // needed for strstr to behave 430 | assert(pid != NULL); 431 | 432 | processList = NULL; 433 | 434 | foundCount = 0; 435 | 436 | // Get the list of all processes. 437 | 438 | err = GetBSDProcessList(&processList, &processCount); 439 | 440 | if (err == 0) { 441 | 442 | // Search for an exact match. 443 | 444 | for (processIndex = 0; processIndex < processCount; processIndex++) { 445 | if ( strcmp(processList[processIndex].kp_proc.p_comm, processName) == 0 ) { 446 | *pid = processList[processIndex].kp_proc.p_pid; 447 | foundCount = 1; 448 | break; 449 | } 450 | } 451 | 452 | // If that failed, search for a substring match. 453 | 454 | if (foundCount == 0) { 455 | for (processIndex = 0; processIndex < processCount; processIndex++) { 456 | if ( strstr(processList[processIndex].kp_proc.p_comm, processName) != NULL ) { 457 | *pid = processList[processIndex].kp_proc.p_pid; 458 | foundCount += 1; 459 | } 460 | } 461 | } 462 | 463 | // If we found more than 1, that's ambiguous and we error out. 464 | 465 | if (foundCount > 1) { 466 | fprintf(stderr, "%s: '%s' does not denote a unique process.\n", gProgramName, processName); 467 | err = EINVAL; 468 | } 469 | } 470 | 471 | // If still not found, try processName as a PID. 472 | 473 | if ( (err == 0) && (foundCount == 0) ) { 474 | char * firstInvalid; 475 | 476 | *pid = (pid_t) strtol(processName, &firstInvalid, 10); 477 | if ( (processName[0] == 0) || (*firstInvalid != 0) ) { 478 | err = EINVAL; 479 | } 480 | } 481 | 482 | free(processList); 483 | 484 | return err; 485 | } 486 | 487 | static void PrintUsage(void) 488 | { 489 | fprintf(stderr, "usage: %s [options] [ [ pid | name ]... ]\n", gProgramName); 490 | fprintf(stderr, " Send, Receive, SendOnce, PortSet, DeadName = right reference counts\n"); 491 | fprintf(stderr, " DNR = dead name request\n"); 492 | fprintf(stderr, " -w wide output, with lots of extra info\n"); 493 | fprintf(stderr, " flg = N (no senders) P (port dead) S (send rights)\n"); 494 | fprintf(stderr, " seqno = sequence number\n"); 495 | fprintf(stderr, " mscount = make-send count\n"); 496 | fprintf(stderr, " qlimit = queue limit\n"); 497 | fprintf(stderr, " msgcount = message count\n"); 498 | fprintf(stderr, " sorights = send-once right count\n"); 499 | fprintf(stderr, " pset = port set count\n"); 500 | } 501 | 502 | int main(int argc, char * argv[]) 503 | { 504 | kern_return_t err; 505 | bool verbose; 506 | int ch; 507 | int argIndex; 508 | 509 | // Set gProgramName to the last path component of argv[0] 510 | 511 | gProgramName = strrchr(argv[0], '/'); 512 | if (gProgramName == NULL) { 513 | gProgramName = argv[0]; 514 | } else { 515 | gProgramName += 1; 516 | } 517 | 518 | // Parse our options. 519 | 520 | verbose = false; 521 | do { 522 | ch = getopt(argc, argv, "w"); 523 | if (ch != -1) { 524 | switch (ch) { 525 | case 'w': 526 | verbose = true; 527 | break; 528 | case '?': 529 | default: 530 | PrintUsage(); 531 | exit(EXIT_FAILURE); 532 | break; 533 | } 534 | } 535 | } while (ch != -1); 536 | 537 | // Handle the remaining arguments. If none, we work against ourselves. 538 | // Otherwise each string is treated as a process name, and we look that 539 | // up using FindProcessByName. 540 | 541 | if (argv[optind] == NULL) { 542 | err = PrintProcessPortSpace(getpid(), verbose); 543 | } else { 544 | for (argIndex = optind; argIndex < argc; argIndex++) { 545 | pid_t pid; 546 | 547 | if (argIndex > optind) { 548 | fprintf(stdout, "\n"); 549 | } 550 | if (argv[argIndex][0] == 0) { 551 | err = EINVAL; 552 | } else { 553 | err = FindProcessByName(argv[argIndex], &pid); 554 | } 555 | if (err == 0) { 556 | fprintf(stdout, "Mach ports for '%s' (%lld):\n", argv[argIndex], (long long) pid); 557 | fprintf(stdout, "\n"); 558 | 559 | err = PrintProcessPortSpace(pid, verbose); 560 | } 561 | 562 | if (err != 0) { 563 | break; 564 | } 565 | } 566 | } 567 | 568 | if (err != 0) { 569 | fprintf(stderr, "%s: Failed with error %d.\n", gProgramName, err); 570 | } 571 | return (err == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 572 | } 573 | -------------------------------------------------------------------------------- /sys/machtrace.d: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | #pragma D option quiet 4 | * usage example: 5 | * dtrace -x dynvarsize=4m -x evaltime=exec -Cs machtrace.d -c ls 6 | * dtrace -x dynvarsize=4m -x evaltime=exec -Cs machtrace.d -p 10 7 | */ 8 | 9 | /* 10 | * trace system calls together with mach traps 11 | */ 12 | 13 | /* 14 | * Command line arguments 15 | */ 16 | inline int OPT_follow = 1; 17 | inline int OPT_printid = 1; 18 | inline int OPT_relative = 1; 19 | inline int OPT_elapsed = 1; 20 | inline int OPT_cpu = 0; 21 | inline int OPT_counts = 1; 22 | inline int OPT_stack = 0; 23 | 24 | #ifdef EXECNAME 25 | inline int OPT_name = 1; 26 | inline string NAME = NAME; 27 | #else 28 | inline int OPT_name = 0; 29 | inline string NAME = ""; 30 | #endif 31 | 32 | inline int OPT_trace = 0; 33 | inline string TRACE = ""; 34 | 35 | dtrace:::BEGIN 36 | /$target/ 37 | { 38 | printf("tracing pid %d\n", $target); 39 | } 40 | 41 | dtrace:::BEGIN 42 | { 43 | /* print header */ 44 | /* OPT_printid ? printf("%-8s ","PID/LWP") : 1; */ 45 | OPT_printid ? printf("\t%-8s ","PID/THRD") : 1; 46 | OPT_relative ? printf("%8s ","RELATIVE") : 1; 47 | OPT_elapsed ? printf("%7s ","ELAPSD") : 1; 48 | OPT_cpu ? printf("%6s ","CPU") : 1; 49 | printf("SYSCALL(args) \t\t = return\n"); 50 | 51 | /* globals */ 52 | trackedpid[pid] = 0; 53 | self->child = 0; 54 | this->type = 0; 55 | } 56 | 57 | /* 58 | * Syscalls that were started before DTrace attached 59 | */ 60 | 61 | syscall:::return, 62 | mach_trap:::return 63 | /!self->start && (pid == $target || ppid == $target)/ 64 | { 65 | self->code = errno == 0 ? "" : "Err#"; 66 | 67 | printf("UNEXPECTED RETURN: %5d 0x%x %s %s(XXX)\t\t = %d errno = %d\n", 68 | pid, tid, probeprov, probefunc ,(int)arg0, (int)errno); 69 | OPT_stack ? ustack() : 1; 70 | OPT_stack ? trace("\n") : 1; 71 | } 72 | 73 | /* 74 | * Save syscall entry info 75 | */ 76 | 77 | /* MacOS X: notice first appearance of child from fork. Its parent 78 | fires syscall::*fork:return in the ususal way (see below) */ 79 | syscall:::entry 80 | /OPT_follow && trackedpid[ppid] == -1 && 0 == self->child/ 81 | { 82 | /* set as child */ 83 | self->child = 1; 84 | 85 | /* print output */ 86 | self->code = errno == 0 ? "" : "Err#"; 87 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 88 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 89 | OPT_relative ? printf("%8d: ",vtimestamp/1000) : 1; 90 | OPT_elapsed ? printf("%7d: ",0) : 1; 91 | OPT_cpu ? printf("%6d ",0) : 1; 92 | printf("%s()\t\t = %d %s%d\n","fork", 93 | 0,self->code,(int)errno); 94 | } 95 | 96 | /* MacOS X: notice first appearance of child and parent from vfork */ 97 | syscall:::entry 98 | /OPT_follow && trackedpid[ppid] > 0 && 0 == self->child/ 99 | { 100 | /* set as child */ 101 | this->vforking_tid = trackedpid[ppid]; 102 | self->child = (this->vforking_tid == tid) ? 0 : 1; 103 | 104 | /* print output */ 105 | self->code = errno == 0 ? "" : "Err#"; 106 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 107 | OPT_printid ? printf("%5d/0x%x: ",(this->vforking_tid == tid) ? ppid : pid,tid) : 1; 108 | OPT_relative ? printf("%8d: ",vtimestamp/1000) : 1; 109 | OPT_elapsed ? printf("%7d: ",0) : 1; 110 | OPT_cpu ? printf("%6d ",0) : 1; 111 | printf("%s()\t\t = %d %s%d\n","vfork", 112 | (this->vforking_tid == tid) ? pid : 0,self->code,(int)errno); 113 | } 114 | 115 | syscall:::entry, 116 | mach_trap:::entry 117 | 118 | /($target && pid == $target) || 119 | (OPT_name && NAME == strstr(NAME, execname)) || 120 | (OPT_name && execname == strstr(execname, NAME)) || 121 | (self->child)/ 122 | { 123 | /* set start details */ 124 | self->start = timestamp; 125 | self->vstart = vtimestamp; 126 | self->arg0 = arg0; 127 | self->arg1 = arg1; 128 | self->arg2 = arg2; 129 | 130 | /* count occurances */ 131 | OPT_counts == 1 ? @Counts[probeprov, probefunc] = count() : 1; 132 | } 133 | 134 | syscall::select:entry, 135 | syscall::mmap:entry, 136 | syscall::pwrite:entry, 137 | syscall::pread:entry 138 | /($target && pid == $target) || 139 | (OPT_name && NAME == strstr(NAME, execname)) || 140 | (OPT_name && execname == strstr(execname, NAME)) || 141 | (self->child)/ 142 | { 143 | self->arg3 = arg3; 144 | self->arg4 = arg4; 145 | self->arg5 = arg5; 146 | } 147 | 148 | /* 149 | * Follow children 150 | */ 151 | syscall::fork:entry 152 | /OPT_follow && self->start/ 153 | { 154 | /* track this parent process */ 155 | trackedpid[pid] = -1; 156 | } 157 | 158 | syscall::vfork:entry 159 | /OPT_follow && self->start/ 160 | { 161 | /* track this parent process */ 162 | trackedpid[pid] = tid; 163 | } 164 | 165 | /* syscall::rexit:entry */ 166 | syscall::exit:entry 167 | { 168 | /* forget child */ 169 | self->child = 0; 170 | trackedpid[pid] = 0; 171 | } 172 | 173 | /* 174 | * Check for syscall tracing 175 | */ 176 | syscall:::entry 177 | /OPT_trace && probefunc != TRACE/ 178 | { 179 | /* drop info */ 180 | self->start = 0; 181 | self->vstart = 0; 182 | self->arg0 = 0; 183 | self->arg1 = 0; 184 | self->arg2 = 0; 185 | self->arg3 = 0; 186 | self->arg4 = 0; 187 | self->arg5 = 0; 188 | } 189 | 190 | /* 191 | * Print return data 192 | */ 193 | 194 | /* 195 | * NOTE: 196 | * The following code is written in an intentionally repetetive way. 197 | * The first versions had no code redundancies, but performed badly during 198 | * benchmarking. The priority here is speed, not cleverness. I know there 199 | * are many obvious shortcuts to this code, Ive tried them. This style has 200 | * shown in benchmarks to be the fastest (fewest probes, fewest actions). 201 | */ 202 | 203 | /* print 3 args, return as hex */ 204 | syscall::sigprocmask:return 205 | /self->start/ 206 | { 207 | /* calculate elapsed time */ 208 | this->elapsed = timestamp - self->start; 209 | self->start = 0; 210 | this->cpu = vtimestamp - self->vstart; 211 | self->vstart = 0; 212 | self->code = errno == 0 ? "" : "Err#"; 213 | 214 | /* print optional fields */ 215 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 216 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 217 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 218 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 219 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 220 | 221 | /* print main data */ 222 | printf("%s(0x%X, 0x%X, 0x%X)\t\t = 0x%X %s%d\n",probefunc, 223 | (int)self->arg0,self->arg1,self->arg2,(int)arg0, 224 | self->code,(int)errno); 225 | OPT_stack ? ustack() : 1; 226 | OPT_stack ? trace("\n") : 1; 227 | self->arg0 = 0; 228 | self->arg1 = 0; 229 | self->arg2 = 0; 230 | } 231 | 232 | /* print 3 args, arg0 as a string */ 233 | syscall::execve:return, 234 | syscall::stat:return, 235 | syscall::stat64:return, 236 | syscall::lstat:return, 237 | syscall::lstat64:return, 238 | syscall::access:return, 239 | syscall::mkdir:return, 240 | syscall::chdir:return, 241 | syscall::chroot:return, 242 | syscall::getattrlist:return, /* XXX 5 arguments */ 243 | syscall::chown:return, 244 | syscall::lchown:return, 245 | syscall::chflags:return, 246 | syscall::readlink:return, 247 | syscall::utimes:return, 248 | syscall::pathconf:return, 249 | syscall::truncate:return, 250 | syscall::getxattr:return, 251 | syscall::setxattr:return, 252 | syscall::removexattr:return, 253 | syscall::unlink:return, 254 | syscall::open:return, 255 | syscall::open_nocancel:return 256 | /self->start/ 257 | { 258 | /* calculate elapsed time */ 259 | this->elapsed = timestamp - self->start; 260 | self->start = 0; 261 | this->cpu = vtimestamp - self->vstart; 262 | self->vstart = 0; 263 | self->code = errno == 0 ? "" : "Err#"; 264 | 265 | /* print optional fields */ 266 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 267 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 268 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 269 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 270 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 271 | 272 | /* print main data */ 273 | printf("%s(\"%S\", 0x%X, 0x%X)\t\t = %d %s%d\n",probefunc, 274 | copyinstr(self->arg0),self->arg1,self->arg2,(int)arg0, 275 | self->code,(int)errno); 276 | OPT_stack ? ustack() : 1; 277 | OPT_stack ? trace("\n") : 1; 278 | self->arg0 = 0; 279 | self->arg1 = 0; 280 | self->arg2 = 0; 281 | } 282 | 283 | /* print 3 args, arg1 as a string */ 284 | syscall::write:return, 285 | syscall::write_nocancel:return, 286 | syscall::read:return, 287 | syscall::read_nocancel:return 288 | /self->start/ 289 | { 290 | /* calculate elapsed time */ 291 | this->elapsed = timestamp - self->start; 292 | self->start = 0; 293 | this->cpu = vtimestamp - self->vstart; 294 | self->vstart = 0; 295 | self->code = errno == 0 ? "" : "Err#"; 296 | 297 | /* print optional fields */ 298 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 299 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 300 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 301 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 302 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 303 | 304 | /* print main data */ 305 | printf("%s(0x%X, \"%S\", 0x%X)\t\t = %d %s%d\n",probefunc,self->arg0, 306 | arg0 == -1 ? "" : stringof(copyin(self->arg1,arg0)),self->arg2,(int)arg0, 307 | self->code,(int)errno); 308 | OPT_stack ? ustack() : 1; 309 | OPT_stack ? trace("\n") : 1; 310 | self->arg0 = 0; 311 | self->arg1 = 0; 312 | self->arg2 = 0; 313 | } 314 | 315 | /* print 2 args, arg0 and arg1 as strings */ 316 | syscall::rename:return, 317 | syscall::symlink:return, 318 | syscall::link:return 319 | /self->start/ 320 | { 321 | /* calculate elapsed time */ 322 | this->elapsed = timestamp - self->start; 323 | self->start = 0; 324 | this->cpu = vtimestamp - self->vstart; 325 | self->vstart = 0; 326 | self->code = errno == 0 ? "" : "Err#"; 327 | 328 | /* print optional fields */ 329 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 330 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 331 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 332 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 333 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 334 | 335 | /* print main data */ 336 | printf("%s(\"%S\", \"%S\")\t\t = %d %s%d\n",probefunc, 337 | copyinstr(self->arg0), copyinstr(self->arg1), 338 | (int)arg0,self->code,(int)errno); 339 | OPT_stack ? ustack() : 1; 340 | OPT_stack ? trace("\n") : 1; 341 | self->arg0 = 0; 342 | self->arg1 = 0; 343 | self->arg2 = 0; 344 | } 345 | 346 | /* print 0 arg output */ 347 | syscall::*fork:return 348 | /self->start/ 349 | { 350 | /* calculate elapsed time */ 351 | this->elapsed = timestamp - self->start; 352 | self->start = 0; 353 | this->cpu = vtimestamp - self->vstart; 354 | self->vstart = 0; 355 | self->code = errno == 0 ? "" : "Err#"; 356 | 357 | /* print optional fields */ 358 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 359 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 360 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 361 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 362 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 363 | 364 | /* print main data */ 365 | printf("%s()\t\t = %d %s%d\n",probefunc, 366 | (int)arg0,self->code,(int)errno); 367 | OPT_stack ? ustack() : 1; 368 | OPT_stack ? trace("\n") : 1; 369 | self->arg0 = 0; 370 | self->arg1 = 0; 371 | self->arg2 = 0; 372 | } 373 | 374 | /* print 1 arg output */ 375 | syscall::close:return, 376 | syscall::close_nocancel:return 377 | /self->start/ 378 | { 379 | /* calculate elapsed time */ 380 | this->elapsed = timestamp - self->start; 381 | self->start = 0; 382 | this->cpu = vtimestamp - self->vstart; 383 | self->vstart = 0; 384 | self->code = errno == 0 ? "" : "Err#"; 385 | 386 | /* print optional fields */ 387 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 388 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 389 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 390 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 391 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 392 | 393 | /* print main data */ 394 | printf("%s(0x%X)\t\t = %d %s%d\n",probefunc,self->arg0, 395 | (int)arg0,self->code,(int)errno); 396 | OPT_stack ? ustack() : 1; 397 | OPT_stack ? trace("\n") : 1; 398 | self->arg0 = 0; 399 | self->arg1 = 0; 400 | self->arg2 = 0; 401 | } 402 | 403 | /* print 2 arg output */ 404 | syscall::utimes:return, 405 | syscall::munmap:return 406 | /self->start/ 407 | { 408 | /* calculate elapsed time */ 409 | this->elapsed = timestamp - self->start; 410 | self->start = 0; 411 | this->cpu = vtimestamp - self->vstart; 412 | self->vstart = 0; 413 | self->code = errno == 0 ? "" : "Err#"; 414 | 415 | /* print optional fields */ 416 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 417 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 418 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 419 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 420 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 421 | 422 | /* print main data */ 423 | printf("%s(0x%X, 0x%X)\t\t = %d %s%d\n",probefunc,self->arg0, 424 | self->arg1,(int)arg0,self->code,(int)errno); 425 | OPT_stack ? ustack() : 1; 426 | OPT_stack ? trace("\n") : 1; 427 | self->arg0 = 0; 428 | self->arg1 = 0; 429 | self->arg2 = 0; 430 | } 431 | 432 | /* print pread/pwrite with 4 arguments */ 433 | syscall::pread*:return, 434 | syscall::pwrite*:return 435 | /self->start/ 436 | { 437 | /* calculate elapsed time */ 438 | this->elapsed = timestamp - self->start; 439 | self->start = 0; 440 | this->cpu = vtimestamp - self->vstart; 441 | self->vstart = 0; 442 | self->code = errno == 0 ? "" : "Err#"; 443 | 444 | /* print optional fields */ 445 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 446 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 447 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 448 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 449 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 450 | 451 | /* print main data */ 452 | printf("%s(0x%X, \"%S\", 0x%X, 0x%X)\t\t = %d %s%d\n",probefunc,self->arg0, 453 | stringof(copyin(self->arg1,self->arg2)),self->arg2,self->arg3,(int)arg0,self->code,(int)errno); 454 | OPT_stack ? ustack() : 1; 455 | OPT_stack ? trace("\n") : 1; 456 | self->arg0 = 0; 457 | self->arg1 = 0; 458 | self->arg2 = 0; 459 | self->arg3 = 0; 460 | } 461 | 462 | /* print select with 5 arguments */ 463 | syscall::select:return 464 | /self->start/ 465 | { 466 | /* calculate elapsed time */ 467 | this->elapsed = timestamp - self->start; 468 | self->start = 0; 469 | this->cpu = vtimestamp - self->vstart; 470 | self->vstart = 0; 471 | self->code = errno == 0 ? "" : "Err#"; 472 | 473 | /* print optional fields */ 474 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 475 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 476 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 477 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 478 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 479 | 480 | /* print main data */ 481 | printf("%s(0x%X, 0x%X, 0x%X, 0x%X, 0x%X)\t\t = %d %s%d\n",probefunc,self->arg0, 482 | self->arg1,self->arg2,self->arg3,self->arg4,(int)arg0,self->code,(int)errno); 483 | OPT_stack ? ustack() : 1; 484 | OPT_stack ? trace("\n") : 1; 485 | self->arg0 = 0; 486 | self->arg1 = 0; 487 | self->arg2 = 0; 488 | self->arg3 = 0; 489 | self->arg4 = 0; 490 | } 491 | 492 | /* mmap has 6 arguments */ 493 | syscall::mmap:return 494 | /self->start/ 495 | { 496 | /* calculate elapsed time */ 497 | this->elapsed = timestamp - self->start; 498 | self->start = 0; 499 | this->cpu = vtimestamp - self->vstart; 500 | self->vstart = 0; 501 | self->code = errno == 0 ? "" : "Err#"; 502 | 503 | /* print optional fields */ 504 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 505 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 506 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 507 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 508 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 509 | 510 | /* print main data */ 511 | printf("%s(0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X)\t\t = 0x%X %s%d\n",probefunc,self->arg0, 512 | self->arg1,self->arg2,self->arg3,self->arg4,self->arg5, (int)arg0,self->code,(int)errno); 513 | OPT_stack ? ustack() : 1; 514 | OPT_stack ? trace("\n") : 1; 515 | self->arg0 = 0; 516 | self->arg1 = 0; 517 | self->arg2 = 0; 518 | self->arg3 = 0; 519 | self->arg4 = 0; 520 | self->arg5 = 0; 521 | } 522 | 523 | /* print 3 arg output - default */ 524 | syscall:::return, 525 | mach_trap:::return 526 | /self->start/ 527 | { 528 | /* calculate elapsed time */ 529 | this->elapsed = timestamp - self->start; 530 | self->start = 0; 531 | this->cpu = vtimestamp - self->vstart; 532 | self->vstart = 0; 533 | self->code = errno == 0 ? "" : "Err#"; 534 | 535 | /* print optional fields */ 536 | /* OPT_printid ? printf("%5d/%d: ",pid,tid) : 1; */ 537 | OPT_printid ? printf("%5d/0x%x: ",pid,tid) : 1; 538 | OPT_relative ? printf("%8d ",vtimestamp/1000) : 1; 539 | OPT_elapsed ? printf("%7d ",this->elapsed/1000) : 1; 540 | OPT_cpu ? printf("%6d ",this->cpu/1000) : 1; 541 | 542 | /* print main data */ 543 | printf("%s %s(0x%X, 0x%X, 0x%X)\t\t = %d %s%d\n",probeprov,probefunc,self->arg0, 544 | self->arg1,self->arg2,(int)arg0,self->code,(int)errno); 545 | OPT_stack ? ustack() : 1; 546 | OPT_stack ? trace("\n") : 1; 547 | self->arg0 = 0; 548 | self->arg1 = 0; 549 | self->arg2 = 0; 550 | } 551 | 552 | dtrace:::END 553 | { 554 | OPT_counts == 1 ? printa(@Counts) : 1; 555 | } 556 | -------------------------------------------------------------------------------- /sys/portsnoop.d: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/dtrace -Cs 2 | 3 | #define OSX_10_8_2 4 | 5 | #ifdef OSX_10_7_3 6 | #define ipc_space_kernel (void *)0xffffff801341bf40 /* lookup in gdb */ 7 | #endif 8 | #ifdef OSX_10_7_4 9 | #define ipc_space_kernel (void *)0xffffff80115b9f40 10 | #endif 11 | #ifdef OSX_10_8_2 12 | #define ipc_space_kernel (void *)0xffffff8043cc6fc0 13 | #endif 14 | #define space_comm(space) ((proc_t)space->is_task->bsd_info)->p_comm 15 | #define IO_BITS_ACTIVE 0x80000000 16 | 17 | ipc_kmsg_send:entry 18 | { 19 | //trace(execname); 20 | this->h = ((struct ipc_kmsg *)arg0)->ikm_header; 21 | this->localp = this->h->msgh_local_port; 22 | this->remotep = this->h->msgh_remote_port; 23 | this->rvalid = this->remotep->ip_object.io_bits & IO_BITS_ACTIVE; 24 | this->rspace = this->remotep->data.receiver; 25 | } 26 | 27 | /* 28 | ipc_kmsg_send:entry 29 | /this->rvalid != 0/ 30 | { 31 | this->rspace = this->remotep->data.receiver; 32 | printf("execname %s", execname); 33 | printf(" space %p", this->rspace); 34 | printf(" localp %p", this->localp); 35 | printf(" remotep %p", this->remotep); 36 | } 37 | */ 38 | 39 | #if 0 40 | #ifndef FILTER_COMM 41 | ipc_kmsg_send:entry 42 | /this->rspace != ipc_space_kernel/ 43 | { 44 | printf("%p -> %p (%s)", this->localp, this->remotep, space_comm(this->rspace)); 45 | } 46 | #endif 47 | #endif 48 | 49 | ipc_kmsg_send:entry 50 | /this->rspace == ipc_space_kernel 51 | #ifdef FILTER_COMM 52 | && execname == FILTER_COMM 53 | #endif 54 | / 55 | { 56 | printf("%p -> %p (%s -> kernel)", this->localp, this->remotep, execname); 57 | #if 0 58 | self->mon = 1; 59 | #endif 60 | } 61 | 62 | #if 0 63 | fbt::: /self->mon == 1/ {} 64 | 65 | ipc_kmsg_send:return 66 | /self->mon == 1/ 67 | { 68 | self->mon = 0; 69 | } 70 | #endif 71 | 72 | ipc_kmsg_send:entry 73 | /this->rvalid != 0 && this->rspace != ipc_space_kernel 74 | && this->rspace->is_task == 0/ 75 | { 76 | printf("%s -> NULL TASK (space %p)", execname, this->rspace); 77 | /* 78 | stack(); 79 | */ 80 | } 81 | 82 | ipc_kmsg_send:entry 83 | /this->rvalid != 0 && this->rspace != ipc_space_kernel && this->rspace->is_task != 0 84 | #ifdef FILTER_COMM 85 | && (space_comm(this->rspace) == FILTER_COMM || execname == FILTER_COMM) 86 | #endif 87 | / 88 | { 89 | printf("%p -> %p (%s -> %s)", this->localp, this->remotep, execname, space_comm(this->rspace)); 90 | @[execname, this->localp, this->remotep, ustack()] = count(); 91 | } 92 | -------------------------------------------------------------------------------- /sys/sockets.d: -------------------------------------------------------------------------------- 1 | 2 | #pragma D option quiet 3 | #pragma D option switchrate=10hz 4 | 5 | /* 6 | * deltas are in microseconds (1 us = 1/1000 ms) 7 | */ 8 | 9 | inline int af_unix = 1; /* AF_UNIX defined in sys/socket.h */ 10 | inline int af_inet = 2; /* AF_INET defined in bsd/sys/socket.h */ 11 | inline int af_inet6 = 30; /* AF_INET6 defined in bsd/sys/socket.h */ 12 | 13 | /* 14 | * OSX DTrace stubs 15 | */ 16 | 17 | #define NTOHS(X) ((((X) & 0xFF00) >> 8) | (((X) & 0xFF)) << 8) 18 | 19 | /* 20 | * Convert an IPv4 address into a dotted quad decimal string. 21 | * Until the inet_ntoa() functions are available from DTrace, this is 22 | * converted using the existing strjoin() and lltostr(). It's done in 23 | * two parts to avoid exhausting DTrace registers in one line of code. 24 | */ 25 | #define INET_NTOA(ADDR_PTR, ADDR_DEST) \ 26 | this->a = (uint8_t *)&(ADDR_PTR); \ 27 | this->addr1 = strjoin(lltostr(this->a[0] + 0ULL), strjoin(".", strjoin(lltostr(this->a[1] + 0ULL), "."))); \ 28 | this->addr2 = strjoin(lltostr(this->a[2] + 0ULL), strjoin(".", lltostr(this->a[3] + 0ULL))); \ 29 | (ADDR_DEST) = strjoin(this->addr1, this->addr2); 30 | 31 | #define SOCKADDR_UN(P) \ 32 | this->sun = (struct sockaddr_un *)P; \ 33 | self->address = this->sun->sun_path; \ 34 | self->port = 0; 35 | 36 | #define SOCKADDR_IN(P) \ 37 | this->sin = (struct sockaddr_in *)P; \ 38 | INET_NTOA(this->sin->sin_addr, self->address); \ 39 | self->port = NTOHS(this->sin->sin_port); 40 | 41 | #ifndef IPV6_VERBOSE 42 | #define SOCKADDR_IN6(P) \ 43 | this->sin6 = (struct sockaddr_in6 *)P; \ 44 | self->port = NTOHS(this->sin6->sin6_port); \ 45 | self->address = self->port == 0 ? "::?" : "?"; 46 | #else 47 | #define SOCKADDR_IN6(P) \ 48 | this->sin6 = (struct sockaddr_in6 *)P; \ 49 | self->port = NTOHS(this->sin6->sin6_port); \ 50 | self->address = self->port == 0 ? "::?" : "tracememd"; \ 51 | tracemem((user_addr_t)&this->sin6->sin6_addr, 16); 52 | #endif 53 | 54 | #define ADDR_INIT(ptr, len) \ 55 | this->s = (struct sockaddr *)copyin(ptr, len); \ 56 | self->address = "(unknown)"; \ 57 | self->port = 0; \ 58 | self->family = this->s->sa_family; \ 59 | 60 | #define ADDR_CLEANUP() \ 61 | self->family = 0; \ 62 | self->address = 0; \ 63 | self->port = 0; \ 64 | self->start = 0; 65 | 66 | #define PRINT_UN() \ 67 | this->delta = (timestamp - self->start) / 1000; \ 68 | printf("%s(un) %s(%d) %s %d %s\n", probefunc, execname, pid, self->address, this->delta, STR(err, errno)); \ 69 | ADDR_CLEANUP(); 70 | 71 | #define PRINT() \ 72 | this->delta = (timestamp - self->start) / 1000; \ 73 | printf("%s(%s=%d) %s(%d) %s:%d %d %s\n", probefunc, AF(self->family), self->s, execname, pid, \ 74 | self->address, self->port, this->delta, STR(err, errno)); \ 75 | ADDR_CLEANUP(); 76 | 77 | #define STR(table, value) (table[value] != NULL ? table[value] : lltostr(value)) 78 | #define AF(x) STR(af, x) 79 | #define SOTYPE(x) STR(so_type, x) 80 | 81 | dtrace:::BEGIN 82 | { 83 | /* Add translations as desired from /usr/include/sys/errno.h */ 84 | err[0] = "ok"; 85 | err[EINTR] = "EINTR"; 86 | err[EIO] = "EIO"; 87 | err[EACCES] = "EACCES"; 88 | err[ENETDOWN] = "ENETDOWN"; 89 | err[ENETUNREACH] = "ENETUNREACH"; 90 | err[ECONNRESET] = "ECONNRESET"; 91 | err[ECONNREFUSED] = "ECONNREFUSED"; 92 | err[ETIMEDOUT] = "ETIMEDOUT"; 93 | err[EHOSTDOWN] = "EHOSTDOWN"; 94 | err[EHOSTUNREACH] = "EHOSTUNREACH"; 95 | err[EINPROGRESS] = "EINPROGRESS"; 96 | 97 | af[-1] = "UNDEFINED"; 98 | af[af_unix] = "un"; 99 | af[af_inet] = "in4"; 100 | af[af_inet6] = "in6"; 101 | 102 | so_type[-1] = "UNDEFINED"; 103 | so_type[0] = "UNDEFINED"; 104 | so_type[1] = "stream"; 105 | so_type[2] = "dgram"; 106 | } 107 | 108 | dtrace:::ERROR 109 | /arg4 == DTRACEFLT_UPRIV/ 110 | { 111 | printf("user fault: %s\n", execname); 112 | } 113 | 114 | #define socket_syscall_genprobes(func, entry_ptr, entry_len) \ 115 | syscall::func:entry { self->s = arg0; ADDR_INIT(entry_ptr, entry_len); self->start = timestamp; } \ 116 | syscall::func:entry /self->family == af_inet/ {SOCKADDR_IN(this->s);} \ 117 | syscall::func:entry /self->family == af_inet6/ {SOCKADDR_IN6(this->s);} \ 118 | syscall::func:entry /self->family == af_unix/ {SOCKADDR_UN(this->s);} \ 119 | syscall::func:return /self->family == af_unix/ {PRINT_UN();} \ 120 | syscall::func:return /self->family/ {PRINT();} 121 | 122 | socket_syscall_genprobes(connect*, arg1, arg2) 123 | socket_syscall_genprobes(bind, arg1, arg2) 124 | 125 | syscall::socket:entry 126 | { 127 | self->family = arg0; 128 | self->so_type = arg1; 129 | } 130 | 131 | syscall::socket:return 132 | /self->so_type/ 133 | { 134 | printf("%s(%s, %s) %s(%d) = %d\n", probefunc, AF(self->family), SOTYPE(self->so_type), execname, pid, arg1); 135 | self->so_type = 0; 136 | self->family = 0; 137 | } 138 | 139 | /* 140 | * accept(2) is special: sockaddrs are written between entry and return by the kernel 141 | */ 142 | 143 | syscall::accept*:entry 144 | { 145 | self->sa = arg1; /* kernel will write here later */ 146 | self->lenp = (user_addr_t)arg2; 147 | 148 | self->start = timestamp; 149 | } 150 | 151 | syscall::accept*:return 152 | { 153 | this->len = *(socklen_t *)copyin(self->lenp, sizeof(socklen_t)); 154 | ADDR_INIT(self->sa, this->len); 155 | } 156 | 157 | syscall::accept*:return 158 | /self->family == af_unix/ 159 | { 160 | SOCKADDR_UN(this->s); 161 | PRINT_UN(); 162 | } 163 | 164 | syscall::accept*:return 165 | /self->family == af_inet6/ 166 | { 167 | SOCKADDR_IN6(this->s); 168 | PRINT(); 169 | } 170 | 171 | syscall::accept*:return 172 | /self->family == af_inet/ 173 | { 174 | SOCKADDR_IN(this->s); 175 | PRINT(); 176 | } 177 | 178 | syscall::accept*:return /self->family/ {PRINT();} 179 | -------------------------------------------------------------------------------- /sys/waittrace.d: -------------------------------------------------------------------------------- 1 | proc:::exec-success 2 | /execname == EXECNAME/ 3 | { 4 | trace(execname); 5 | inf = pid; 6 | } 7 | 8 | syscall::mmap:return 9 | /pid == inf/ 10 | { 11 | system(CMD); 12 | exit(0); 13 | } 14 | -------------------------------------------------------------------------------- /xnu/kdebug.gdb: -------------------------------------------------------------------------------- 1 | set logging file /tmp/gdb 2 | set logging on 3 | #set logging overwrite 4 | target darwin-kernel 5 | file /Volumes/KernelDebugKit/mach_kernel 6 | source /tank/proger/dev/darwin/xnu-1699.24.8/kgmacros 7 | source /tank/proger/dev/darwin/xnu-1699.24.8/kgmacros.my 8 | attach 9 | --------------------------------------------------------------------------------