Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ce3dc97
Initial version of pkp, a command to print out via keypaths
Nov 20, 2014
5ccee16
Add an error message, made class invocation more durable.
Nov 20, 2014
72adcb4
Fix help message, clean up python.
Nov 21, 2014
add393f
Initial AE printer
Nov 21, 2014
46a7bed
Clean up the pae command
Nov 21, 2014
756e61d
Missed some errors in a helper.
Nov 21, 2014
bea8bee
If there's no '.', just pass the command to po, and evaluate the firs…
Nov 22, 2014
82da1b4
PEP8: E711 comparison to None should be 'if cond is None:'
Nov 7, 2014
682e0e3
PEP8: E713 test for membership should be 'not in'
Nov 7, 2014
ef123fb
PEP8: E203 whitespace before [,:]
Nov 7, 2014
d7f263c
PEP8: W293 blank line contains whitespace
Nov 7, 2014
6e49f55
PEP8: W291 trailing whitespace
Nov 7, 2014
00190a9
PEP8: W191 indentation contains tabs
Nov 7, 2014
36a78af
PEP8: W292 no newline at end of file
Nov 7, 2014
99b8640
PEP8: W391 blank line at end of file
Nov 7, 2014
a3bdbc0
PEP8: E225 missing whitespace around operator
Nov 7, 2014
ae8f52b
PEP8: E226 missing whitespace around arithmetic operator
Nov 7, 2014
474241b
PEP8: E251 unexpected spaces around keyword / parameter equals
Nov 7, 2014
22f00df
PEP8: E231 missing whitespace after ','
Nov 7, 2014
5ae3069
PEP8: E703 statement ends with a semicolon
Nov 8, 2014
dcf6078
Remove superfluous if parens
Nov 8, 2014
595b2c2
Replace Ivar casts with void * casts
Dec 1, 2014
3c98393
bmessage: use regex breakpoint to match category
kastiglione Dec 4, 2014
72ff99a
Add "Dancing in the Debugger" link to README
kastiglione Dec 9, 2014
423f303
Fix typo and formatting
kastiglione Dec 9, 2014
74b9a61
bmessage: Allow optional category
Dec 10, 2014
4a694f9
Use verbose regex for bmessage input
Dec 10, 2014
e6dc3ed
Use exact name when category is given
Dec 10, 2014
994fd57
Implement pvc with +[UIViewController _printHierarchy], if available
Dec 10, 2014
90a01ad
Merge branch 'master' into feature/KingOfBrian/AccessibiltyTree
Dec 19, 2014
beb9ae2
Fix an issue with 64 bit checks vs NSNotFound. It's not ideal.
Dec 19, 2014
09fb3e5
Constifyish the NSNotFound value on 32 bit systems
Dec 19, 2014
f1f77d5
Fix an issue with integer evaluation
Dec 19, 2014
61f568f
Default the argument to the key window, and update the comment to inf…
Dec 19, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions commands/FBPrintCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import fblldbviewcontrollerhelpers as vcHelpers
import fblldbviewhelpers as viewHelpers
import fblldbobjcruntimehelpers as runtimeHelpers
import fblldbobjecthelpers as objectHelpers

def lldbcommands():
return [
Expand All @@ -28,6 +29,8 @@ def lldbcommands():
FBPrintOnscreenTableViewCells(),
FBPrintInternals(),
FBPrintInstanceVariable(),
FBPrintKeyPath(),
FBPrintAccessibilityTree(),
]

class FBPrintViewHierarchyCommand(fb.FBCommand):
Expand Down Expand Up @@ -272,3 +275,40 @@ def run(self, arguments, options):

printCommand = 'po' if ('@' in ivarTypeEncodingFirstChar) else 'p'
lldb.debugger.HandleCommand('{} (({} *)({}))->{}'.format(printCommand, objectClass, object, ivarName))

class FBPrintKeyPath(fb.FBCommand):
def name(self):
return 'pkp'

def description(self):
return "Print out the value of the key path expression using -valueForKeyPath:"

def args(self):
return [
fb.FBCommandArgument(arg='keypath', type='NSString *', help='The keypath to print'),
]

def run(self, arguments, options):
if len(arguments[0].split('.')) == 1:
print '"' + arguments[0] + '" is not a keypath =('
return

object, keypath = arguments[0].split('.', 1)
printCommand = 'po [{} valueForKeyPath:@"{}"]'.format(object, keypath)
lldb.debugger.HandleCommand(printCommand)

class FBPrintAccessibilityTree(fb.FBCommand):
def name(self):
return 'pae'

def description(self):
return "Print out the accessibility heirarchy. Traverses the accessibilityElements if present, otherwise the subviews."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a triple-space between the sentences, not sure if intended. One is the norm in Chisel.


def args(self):
return [
fb.FBCommandArgument(arg='object', type='id', help='The object to print accessibility information for'),
]

def run(self, arguments, options):
object = fb.evaluateObjectExpression(arguments[0])
return viewHelpers.accessibilityRecursiveDescription(object, "")
28 changes: 27 additions & 1 deletion fblldbobjecthelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,30 @@ def isKindOfClass(obj, className):
return fb.evaluateBooleanExpression(isKindOfClassStr.format(className))

def className(obj):
return fb.evaluateExpressionValue('(id)[(' + obj + ') class]').GetObjectDescription()
return fb.evaluateExpressionValue('(id)[(%s) class]' % (obj)).GetObjectDescription()

def valueForKey(obj, key):
return fb.evaluateExpressionValue('(id)[%s valueForKey:@"%s"]' % (obj, key)).GetObjectDescription()

def isNil(obj):
return obj == "<nil>" or obj == "<object returned empty description>"

def displayValueForKey(obj, key):
value = valueForKey(obj, key)
return "{}='{}'".format(key, value) if not isNil(value) else ""

def displayValueForKeys(obj, keys):
def displayValueForThisObjectKey(key):
return displayValueForKey(obj, key)
return " ".join(map(displayValueForThisObjectKey, keys))

def displayObjectWithString(obj, string):
return "<{}:{} {}>".format(
className(obj),
obj,
string)

def displayObjectWithKeys(obj, keys):
return displayObjectWithString(obj, displayValueForKeys(obj, keys))


70 changes: 67 additions & 3 deletions fblldbviewhelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
# of patent rights can be found in the PATENTS file in the same directory.

import lldb

import re
import fblldbbase as fb
import fblldbobjecthelpers as objectHelpers

def flushCoreAnimationTransaction():
lldb.debugger.HandleCommand('expr (void)[CATransaction flush]')
Expand Down Expand Up @@ -84,6 +85,69 @@ def upwardsRecursiveDescription(view, maxDepth=0):
builder = ""
for viewDescription in recursiveDescription:
builder += currentPrefix + viewDescription + "\n"
currentPrefix += " | "
currentPrefix += " | "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a mistaken edit, unless I'm missing something.


return builder

# GetObjectDescription will try to return the pointer.
# However on UIAccessibilityElements, the result will look like this:
# [UITableViewSectionElement]{0x79eb2280} section: 0 (isHeader: 1)
# [UITableViewCellAccessibilityElement - 0x79eac160] <.....
# So, just get the first hex address
def firstHexInDescription(object):
return re.findall(r'0x[0-9A-F]+', "{}".format(object), re.I)[0]

def evaluateIntegerExpression(expression):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a function by the same name in fblldbbase.py. Can we have one single unified version? Can we use int(s, 0) to get automatic base conversion from the text of the input?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure why int(s,16) was used in the other version. Are we sure it's not broken for values > 10? I think it's broken but went un-detected, since having more than 10 VC's is rare, where over 10 subviews is common.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I put in a fix for evaluating integers that prompted my method, and removed my method. I believe it should be working properly now.

output = fb.evaluateExpression('(int)(' + expression + ')', True).replace('\'', '')
return int (output, 10)

def accessibilityDescription(object):
if isAccessibilityElement(object):
return objectHelpers.displayObjectWithKeys(object, ["accessibilityLabel", "accessibilityValue", "accessibilityHint"])
else:
return objectHelpers.displayObjectWithString(object, "isAccessibilityElement=NO")

def accessibilityElementCount(object):
cmd = "(int)[%s accessibilityElementCount]" % (object)
return evaluateIntegerExpression(cmd)

def isAccessibilityElement(object):
return fb.evaluateBooleanExpression('[(id)%s isAccessibilityElement]' % object)

def accessibilityElementAtIndex(object, index):
cmd = '(id)[%s accessibilityElementAtIndex:%s]' % (object, index)
obj = firstHexInDescription(fb.evaluateExpressionValue(cmd))
return obj

def accessibilityChildren(object):
accessibilityCount = accessibilityElementCount(object)
aeChildren = []
if accessibilityCount != 0x7fffffff:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does 0x7fffffff happen?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0x7fffffff is NSNotFound (on 32 bit systems, whoops). This indicates that the view is not an accessibility container. If it returns 0, the traversal stops, if it returns 0x7fffffff, the subviews tree is traversed.

I'm struggling with my python here, I imagine there's a cleaner way to represent it.

for i in range(0, accessibilityCount):
aeChildren.append(accessibilityElementAtIndex(object, i))
return aeChildren

def subviews(view):
subviewResult = []
responds = fb.evaluateBooleanExpression('[(id)%s respondsToSelector:(SEL)@selector(subviews)]' % view)
if responds:
subviews = fb.evaluateExpression('(id)[%s subviews]' % view)
subviewsCount = evaluateIntegerExpression('[(id)%s count]' % subviews)
if subviewsCount > 0:
for i in range(0, subviewsCount):
subview = fb.evaluateExpression('(id)[%s objectAtIndex:%i]' % (subviews, i))
subviewResult.append(subview)
return subviewResult


def accessibilityRecursiveDescription(object, prefix="", childType=""):
print '%s%s%s' % (prefix, childType, accessibilityDescription(object))
nextPrefix = prefix + ' |'
aeChildren = accessibilityChildren(object)
for ae in aeChildren:
accessibilityRecursiveDescription(ae, nextPrefix, 'A ')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Four space indent here.


if len(aeChildren) == 0:
for subview in subviews(object):
accessibilityRecursiveDescription(subview, nextPrefix, 'S ')