Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
doublerebel committed Mar 29, 2013
0 parents commit 23b8ff9
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#dtrace-json

Traces Objective-C method calls by class in a running process, outputting near-JSON data that can be parsed and sorted.

##Usage:

###Dump malformed JSON to text

*Depends on psgrep: https://github.com/jvz/psgrep*

Attaches to a running process by name and dumps output to file.

$ sudo traceapp AppName.app > tracedump.txt

Press **Ctrl+C** when done collecting data. If traced threads move CPU and lose data, some hand-cleaning of the JSON may be required before parsing.


### Sort and parse dtrace tracedump

*Depends on iced-coffee-script*

Show sorted and indented method calls with stacktrace:

$ iced -I inline cafftrace.iced.coffee tracedump.txt

Output sorted, well-formed JSON:

$ iced -I inline cafftrace.iced.coffee --json tracedump.txt


### Comparing stack traces

Dump each formatted trace to file:

$ iced -I inline cafftrace.iced.coffee tracedump.txt > prettytrace
$ iced -I inline cafftrace.iced.coffee tracedump2.txt > prettytrace-2

Side-by-side wide diff to see where traces diverge:

$ sdiff -w270 prettytrace prettytrace-2


Based off of:

http://stackoverflow.com/questions/10749452/can-the-messages-sent-to-an-object-in-objective-c-be-monitored-or-printed-out/10749819#10749819

http://lists.apple.com/archives/xcode-users/2008/Oct/msg00114.html

**dtrace-json** is MIT licensed. Copyright 2013 Double Rebel.
67 changes: 67 additions & 0 deletions cafftrace.iced.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
fs = require 'fs'
{log} = console


indentChar = "\t"
cutStackOffAt = "Foundation"
stackcut = new RegExp "^#{cutStackOffAt}"


red = (s = '') -> "\u001b[31m#{s}"
green = (s = '') -> "\u001b[32m#{s}"
white = (s = '') -> "\u001b[37m#{s}"

error = (msg) ->
log red "Error: #{msg}"
process.exit()


file = process.argv[process.argv.length - 1]
unless file
error "Requires filename as argument."

await fs.readFile file, defer err, data
if err
error "reading file -- #{err}"

wellformed = data.toString().trim().replace /\n/g, ""
if wellformed[wellformed.length - 1] is ","
wellformed = wellformed.substr 0, wellformed.length - 1
wellformed = "[#{wellformed}]"

unsorted = JSON.parse wellformed
unless unsorted
error "Parsing JSON failed."

sorted = []

for fncall in unsorted
i = fncall.order - 1
sorted[i] = fncall
if fncall.stack
sorted[i].stack = (fncall.stack.trim().replace /\s\s+/g, '\n').split '\n'
sorted[i].stack.shift()

if process.argv[process.argv.length - 2] is '--json'
log sorted
process.exit()

for f in sorted
continue unless f

callstring = ""
indent = ""
level = 0

while level < f.level
indent += indentChar
level++

callstring += green "#{indent}#{f.probemod} #{f.probefunc}" + white()
if f.direction is 'entry'
shortstack = (s for s in f.stack when not stackcut.exec s)
callstring += white "\n#{indent}" + shortstack.join "\n#{indent}"
else callstring += " RETURN\n" + white()
log callstring

log white "Sorted!"
31 changes: 31 additions & 0 deletions manual_call_tree_json.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma D option quiet


self int order, level;


#define CLASSES_PROBE(name) \
//objc$target:SomeClass*::name, \
//objc$target:OtherClass*::name, \
objc$target:Ti*::name


CLASSES_PROBE(entry),
CLASSES_PROBE(return)
{
printf("{\n\t\"probemod\": \"%s\",\n\t\"probefunc\": \"%s\",\n\t\"direction\": \"%s\",\n\t\"pid\": %lld,\n\t\"order\": %d", probemod, probefunc, probename, (long long)tid, ++self->order);
}


CLASSES_PROBE(entry)
{
printf(",\n\t\"level\": %d,\n\t\"stack\": \"", self->level++);
ustack(20);
printf("\"},\n")
}


CLASSES_PROBE(return)
{
printf(",\n\t\"level\": %d\n},\n", --self->level);
}
26 changes: 26 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "dtrace-json",
"version": "0.0.1",
"description": "Transforms dtrace output into sorted JSON",
"main": "cafftrace.iced.coffee",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/doublerebel/dtrace-json"
},
"keywords": [
"dtrace",
"json",
"objc",
"obj-c",
"objective",
"c"
],
"author": "charles@doublerebel.com",
"license": "MIT",
"dependencies": {
"iced-coffee-script": ">1.3.9"
}
}
4 changes: 4 additions & 0 deletions traceapp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

PID="$(psgrep -id $1)"
dtrace -C -s manual_call_tree_json.d -p $PID

0 comments on commit 23b8ff9

Please sign in to comment.