Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

[[Installation](#installation) • [Commands](#commands) • [Custom Commands](#custom-commands) • [Development Workflow](#development-workflow) [Contributing](#contributing) • [License](#license)]

For a comprehensive overview of LLDB, and how Chisel compliments it, read Ari Grant's [Dancing in the Debugger — A Waltz with LLDB](http://www.objc.io/issue-19/lldb-debugging.html) in issue 19 of [objc.io](http://www.objc.io/).

## Installation

```
Expand Down
4 changes: 2 additions & 2 deletions commands/FBAutoLayoutCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ def run(self, arguments, options):
def setBorderOnAmbiguousViewRecursive(view, width, color):
if not fb.evaluateBooleanExpression('[(id)%s isKindOfClass:(Class)[UIView class]]' % view):
return

isAmbiguous = fb.evaluateBooleanExpression('(BOOL)[%s hasAmbiguousLayout]' % view)
if isAmbiguous:
layer = viewHelpers.convertToLayer(view)
lldb.debugger.HandleCommand('expr (void)[%s setBorderWidth:(CGFloat)%s]' % (layer, width))
lldb.debugger.HandleCommand('expr (void)[%s setBorderColor:(CGColorRef)[(id)[UIColor %sColor] CGColor]]' % (layer, color))

subviews = fb.evaluateExpression('(id)[%s subviews]' % view)
subviewsCount = int(fb.evaluateExpression('(int)[(id)%s count]' % subviews))
if subviewsCount > 0:
Expand Down
32 changes: 24 additions & 8 deletions commands/FBDebugCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ def run(self, arguments, options):

objectAddress = int(fb.evaluateObjectExpression(commandForObject), 0)

ivarOffsetCommand = '(ptrdiff_t)ivar_getOffset((Ivar)object_getInstanceVariable((id){}, "{}", 0))'.format(objectAddress, ivarName)
ivarOffsetCommand = '(ptrdiff_t)ivar_getOffset((void*)object_getInstanceVariable((id){}, "{}", 0))'.format(objectAddress, ivarName)
ivarOffset = fb.evaluateIntegerExpression(ivarOffsetCommand)

# A multi-statement command allows for variables scoped to the command, not permanent in the session like $variables.
ivarSizeCommand = ('unsigned int size = 0;'
'char *typeEncoding = (char *)ivar_getTypeEncoding((Ivar)class_getInstanceVariable((Class)object_getClass((id){}), "{}"));'
'char *typeEncoding = (char *)ivar_getTypeEncoding((void*)class_getInstanceVariable((Class)object_getClass((id){}), "{}"));'
'(char *)NSGetSizeAndAlignment(typeEncoding, &size, 0);'
'size').format(objectAddress, ivarName)
ivarSize = int(fb.evaluateExpression(ivarSizeCommand), 0)
Expand Down Expand Up @@ -82,7 +82,17 @@ def args(self):
def run(self, arguments, options):
expression = arguments[0]

match = re.match(r'([-+])*\[(.*) (.*)\]', expression)
methodPattern = re.compile(r"""
(?P<scope>[-+])?
\[
(?P<target>.*?)
(?P<category>\(.+\))?
\s+
(?P<selector>.*)
\]
""", re.VERBOSE)

match = methodPattern.match(expression)

if not match:
print 'Failed to parse expression. Do you even Objective-C?!'
Expand All @@ -93,9 +103,10 @@ def run(self, arguments, options):
print 'Your architecture, {}, is truly fantastic. However, I don\'t currently support it.'.format(arch)
return

methodTypeCharacter = match.group(1)
classNameOrExpression = match.group(2)
selector = match.group(3)
methodTypeCharacter = match.group('scope')
classNameOrExpression = match.group('target')
category = match.group('category')
selector = match.group('selector')

methodIsClassMethod = (methodTypeCharacter == '+')

Expand Down Expand Up @@ -135,7 +146,8 @@ def run(self, arguments, options):
return

breakpointClassName = objc.class_getName(nextClass)
breakpointFullName = '{}[{} {}]'.format(methodTypeCharacter, breakpointClassName, selector)
formattedCategory = category if category else ''
breakpointFullName = '{}[{}{} {}]'.format(methodTypeCharacter, breakpointClassName, formattedCategory, selector)

breakpointCondition = None
if targetIsClass:
Expand All @@ -145,7 +157,11 @@ def run(self, arguments, options):

print 'Setting a breakpoint at {} with condition {}'.format(breakpointFullName, breakpointCondition)

lldb.debugger.HandleCommand('breakpoint set --fullname "{}" --condition "{}"'.format(breakpointFullName, breakpointCondition))
if category:
lldb.debugger.HandleCommand('breakpoint set --fullname "{}" --condition "{}"'.format(breakpointFullName, breakpointCondition))
else:
breakpointPattern = '{}\[{}(\(.+\))? {}\]'.format(methodTypeCharacter, breakpointClassName, selector)
lldb.debugger.HandleCommand('breakpoint set --func-regex "{}" --condition "{}"'.format(breakpointPattern, breakpointCondition))

def classItselfImplementsSelector(klass, selector):
thisMethod = objc.class_getInstanceMethod(klass, selector)
Expand Down
4 changes: 2 additions & 2 deletions commands/FBDisplayCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ def options(self):
def run(self, args, options):
colorClassName = 'UIColor'
isMac = runtimeHelpers.isMacintoshArch()

if isMac:
colorClassName = 'NSColor'

layer = viewHelpers.convertToLayer(args[0])
lldb.debugger.HandleCommand('expr (void)[%s setBorderWidth:(CGFloat)%s]' % (layer, options.width))
lldb.debugger.HandleCommand('expr (void)[%s setBorderColor:(CGColorRef)[(id)[%s %sColor] CGColor]]' % (layer, colorClassName, options.color))
Expand Down
4 changes: 2 additions & 2 deletions commands/FBFindCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def printMatchesInViewOutputStringAndCopyFirstToClipboard(needle, haystack):
view = match.groups()[-1]
className = fb.evaluateExpressionValue('(id)[(' + view + ') class]').GetObjectDescription()
print('{} {}'.format(view, className))
if first == None:
if first is None:
first = view
cmd = 'echo %s | tr -d "\n" | pbcopy' % view
os.system(cmd)
Expand All @@ -125,7 +125,7 @@ def run(self, arguments, options):
if re.match(r'.*' + needle + '.*', a11yLabel, re.IGNORECASE):
print('{} {}'.format(view, a11yLabel))

if first == None:
if first is None:
first = view
cmd = 'echo %s | tr -d "\n" | pbcopy' % first
os.system(cmd)
Expand Down
4 changes: 2 additions & 2 deletions commands/FBFlickerCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ def inputCallback(self, input):
elif input == 'p':
recusionName = 'recursiveDescription'
isMac = runtimeHelpers.isMacintoshArch()

if isMac:
recursionName = '_subtreeDescription'

lldb.debugger.HandleCommand('po [(id)' + oldView + ' ' + recusionName + ']')
else:
print '\nI really have no idea what you meant by \'' + input + '\'... =\\\n'
Expand Down
48 changes: 24 additions & 24 deletions commands/FBInvocationCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def stackStartAddressInSelectedFrame(frame):
return int(frame.EvaluateExpression('($esp + 8)').GetValue())
else:
return int(frame.EvaluateExpression('($ebp + 8)').GetValue())


def findArgAtIndexFromStackFrame(frame, index):
return fb.evaluateExpression('*(int *)' + str(findArgAdressAtIndexFromStackFrame(frame, index)))
Expand Down Expand Up @@ -134,36 +134,36 @@ def prettyPrintInvocation(frame, invocation):
print readableString
else:
if encoding[0] == '{':
encoding = encoding[1:len(encoding)-1]
encoding = encoding[1:]
print (hex(address) + ', address of ' + encoding + ' ' + description).strip()

index += 1

def argumentAsString(frame, address, encoding):
if encoding[0] == '{':
encoding = encoding[1:len(encoding)-1]
encoding = encoding[1:]

encodingMap = {
'c' : 'char',
'i' : 'int',
's' : 'short',
'l' : 'long',
'q' : 'long long',

'C' : 'unsigned char',
'I' : 'unsigned int',
'S' : 'unsigned short',
'L' : 'unsigned long',
'Q' : 'unsigned long long',

'f' : 'float',
'd' : 'double',
'B' : 'bool',
'v' : 'void',
'*' : 'char *',
'@' : 'id',
'#' : 'Class',
':' : 'SEL',
'c': 'char',
'i': 'int',
's': 'short',
'l': 'long',
'q': 'long long',

'C': 'unsigned char',
'I': 'unsigned int',
'S': 'unsigned short',
'L': 'unsigned long',
'Q': 'unsigned long long',

'f': 'float',
'd': 'double',
'B': 'bool',
'v': 'void',
'*': 'char *',
'@': 'id',
'#': 'Class',
':': 'SEL',
}

pointers = ''
Expand Down Expand Up @@ -202,5 +202,5 @@ def argumentAsString(frame, address, encoding):
description = value.GetSummary()
if description:
return type + ': ' + description

return None
65 changes: 55 additions & 10 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 All @@ -49,10 +52,10 @@ def args(self):
def run(self, arguments, options):
maxDepth = int(options.depth)
isMac = runtimeHelpers.isMacintoshArch()
if (arguments[0] == '__keyWindow_dynamic__'):

if arguments[0] == '__keyWindow_dynamic__':
arguments[0] = '(id)[[UIApplication sharedApplication] keyWindow]'

if isMac:
arguments[0] = '(id)[[[[NSApplication sharedApplication] windows] objectAtIndex:0] contentView]'

Expand All @@ -65,9 +68,9 @@ def run(self, arguments, options):
print 'Failed to walk view hierarchy. Make sure you pass a view, not any other kind of object or expression.'
else:
printingMethod = 'recursiveDescription'
if (isMac):
if isMac:
printingMethod = '_subtreeDescription'

description = fb.evaluateExpressionValue('(id)[' + arguments[0] + ' ' + printingMethod + ']').GetObjectDescription()
if maxDepth > 0:
separator = re.escape(" | ")
Expand Down Expand Up @@ -100,10 +103,14 @@ def args(self):

def run(self, arguments, options):
isMac = runtimeHelpers.isMacintoshArch()

if (arguments[0] == '__keyWindow_rootVC_dynamic__'):

if arguments[0] == '__keyWindow_rootVC_dynamic__':
if fb.evaluateBooleanExpression('[UIViewController respondsToSelector:@selector(_printHierarchy)]'):
lldb.debugger.HandleCommand('po [UIViewController _printHierarchy]')
return

arguments[0] = '(id)[(id)[[UIApplication sharedApplication] keyWindow] rootViewController]'
if (isMac):
if isMac:
arguments[0] = '(id)[[[[NSApplication sharedApplication] windows] objectAtIndex:0] contentViewController]'

print vcHelpers.viewControllerRecursiveDescription(arguments[0])
Expand All @@ -123,7 +130,7 @@ def run(self, arguments, options):
def _printIterative(initialValue, generator):
indent = 0
for currentValue in generator(initialValue):
print ' | '*indent + currentValue
print ' | ' * indent + currentValue
indent += 1


Expand Down Expand Up @@ -267,8 +274,46 @@ def run(self, arguments, options):
object = fb.evaluateObjectExpression(commandForObject)
objectClass = fb.evaluateExpressionValue('(id)[(' + object + ') class]').GetObjectDescription()

ivarTypeCommand = '((char *)ivar_getTypeEncoding((Ivar)object_getInstanceVariable((id){}, \"{}\", 0)))[0]'.format(object, ivarName)
ivarTypeCommand = '((char *)ivar_getTypeEncoding((void*)object_getInstanceVariable((id){}, \"{}\", 0)))[0]'.format(object, ivarName)
ivarTypeEncodingFirstChar = fb.evaluateExpression(ivarTypeCommand)

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):
command = arguments[0]
if len(command.split('.')) == 1:
lldb.debugger.HandleCommand("po " + command)
else:
objectToMessage, keypath = command.split('.', 1)
object = fb.evaluateObjectExpression(objectToMessage)
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 and the accessibility inspector is enabled, otherwise the subviews."

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

def run(self, arguments, options):
object = fb.evaluateObjectExpression(arguments[0])
return viewHelpers.accessibilityRecursiveDescription(object, "")
Loading