Skip to content
Merged
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
77ab938
PEP8: E711 comparison to None should be 'if cond is None:'
Nov 7, 2014
3f7bcd1
PEP8: E713 test for membership should be 'not in'
Nov 7, 2014
c8c786d
PEP8: E203 whitespace before [,:]
Nov 7, 2014
150a5ea
PEP8: W293 blank line contains whitespace
Nov 7, 2014
b7dcaea
PEP8: W291 trailing whitespace
Nov 7, 2014
baccc1f
PEP8: W191 indentation contains tabs
Nov 7, 2014
ed5d263
PEP8: W292 no newline at end of file
Nov 7, 2014
7b14d91
PEP8: W391 blank line at end of file
Nov 7, 2014
4dce170
PEP8: E225 missing whitespace around operator
Nov 7, 2014
ada9ea9
PEP8: E226 missing whitespace around arithmetic operator
Nov 7, 2014
365f759
PEP8: E251 unexpected spaces around keyword / parameter equals
Nov 7, 2014
3cc8329
PEP8: E231 missing whitespace after ','
Nov 7, 2014
3dedaf3
PEP8: E703 statement ends with a semicolon
Nov 8, 2014
911fa0d
Remove superfluous if parens
Nov 8, 2014
89358c6
Replace Ivar casts with void * casts
Dec 1, 2014
1b45488
Merge pull request #56 from facebook/void-star-Ivar
arigrant Dec 1, 2014
0b668f8
bmessage: use regex breakpoint to match category
kastiglione Dec 4, 2014
7298b4e
Add "Dancing in the Debugger" link to README
kastiglione Dec 9, 2014
a74d0b5
Fix typo and formatting
kastiglione Dec 9, 2014
3ea6c51
Merge pull request #60 from facebook/mention-objcio
arigrant Dec 9, 2014
ee6c3b2
bmessage: Allow optional category
Dec 10, 2014
6e99fbb
Use verbose regex for bmessage input
Dec 10, 2014
0fbaa0c
Use exact name when category is given
Dec 10, 2014
01d8ac4
Implement pvc with +[UIViewController _printHierarchy], if available
Dec 10, 2014
f9df79c
Merge pull request #58 from facebook/bmessage-categories
kastiglione Dec 17, 2014
544a173
Merge pull request #61 from facebook/pvc_printHierarchy
a2 Dec 17, 2014
fc1a6ef
Tweak casting for mask's [[UIView alloc] initWithFrame:]
Dec 19, 2014
cf1bd13
Add `reload` tip to Development Workflow
kastiglione Dec 19, 2014
3d43a45
Make self referential list more honest
kastiglione Dec 19, 2014
b7ff23f
support x86_64h
samanthamjohn Jan 2, 2015
143a8b4
Remove h from currentArch when arch = x86_64h
samanthamjohn Jan 5, 2015
6c1cfcd
Merge pull request #69 from samjohn/master
kastiglione Jan 5, 2015
031e7f3
Merge pull request #65 from facebook/reload-readme
kastiglione Jan 6, 2015
96e0a64
Merge pull request #64 from facebook/fix-mask-init-expression
kastiglione Jan 6, 2015
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
5 changes: 4 additions & 1 deletion 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 Expand Up @@ -120,7 +122,8 @@ Developing commands, whether for local use or contributing to `Chisel` directly,
3. Execute _command source ~/.lldbinit_ in `LLDB` to source the commands
4. Run the command you are working on
5. Modify the command
6. Repeat steps 3-5 until the command becomes a source of happiness
6. Optionally run `script reload(modulename)`
7. Repeat steps 3-6 until the command becomes a source of happiness

## Contributing
Please contribute any generic commands that you make. If it helps you then it will likely help many others! :D See `CONTRIBUTING.md` to learn how to contribute.
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
24 changes: 14 additions & 10 deletions commands/FBPrintCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,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 @@ -66,9 +66,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 @@ -101,10 +101,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 @@ -124,7 +128,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 @@ -268,7 +272,7 @@ 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'
Expand Down
34 changes: 17 additions & 17 deletions commands/FBVisualizationCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,21 @@ def _showImage(commandForImage):
else:
raise

imageDataAddress = fb.evaluateObjectExpression('UIImagePNGRepresentation((id)' + commandForImage +')')
imageDataAddress = fb.evaluateObjectExpression('UIImagePNGRepresentation((id)' + commandForImage + ')')
imageBytesStartAddress = fb.evaluateExpression('(void *)[(id)' + imageDataAddress + ' bytes]')
imageBytesLength = fb.evaluateExpression('(NSUInteger)[(id)' + imageDataAddress + ' length]')

address = int(imageBytesStartAddress,16)
address = int(imageBytesStartAddress, 16)
length = int(imageBytesLength)

if not (address or length):
print 'Could not get image data.'
return

process = lldb.debugger.GetSelectedTarget().GetProcess()
error = lldb.SBError()
mem = process.ReadMemory(address, length, error)

if error is not None and str(error) != 'success':
print error
else:
Expand Down Expand Up @@ -76,35 +76,35 @@ def _dataIsImage(data):
data = '(' + data + ')'

frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
result = frame.EvaluateExpression('(id)[UIImage imageWithData:' + data + ']');
result = frame.EvaluateExpression('(id)[UIImage imageWithData:' + data + ']')

if result.GetError() is not None and str(result.GetError()) != 'success':
return 0;
return 0
else:
isImage = result.GetValueAsUnsigned() != 0;
isImage = result.GetValueAsUnsigned() != 0
if isImage:
return 1;
return 1
else:
return 0;
return 0

def _dataIsString(data):
data = '(' + data + ')'

frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
result = frame.EvaluateExpression('(NSString*)[[NSString alloc] initWithData:' + data + ' encoding:4]');
result = frame.EvaluateExpression('(NSString*)[[NSString alloc] initWithData:' + data + ' encoding:4]')

if result.GetError() is not None and str(result.GetError()) != 'success':
return 0;
return 0
else:
isString = result.GetValueAsUnsigned() != 0;
isString = result.GetValueAsUnsigned() != 0
if isString:
return 1;
return 1
else:
return 0;
return 0

def _visualize(target):
target = '(' + target + ')'

if fb.evaluateBooleanExpression('(unsigned long)CFGetTypeID((CFTypeRef)' + target + ') == (unsigned long)CGImageGetTypeID()'):
_showImage('(id)[UIImage imageWithCGImage:' + target + ']')
else:
Expand All @@ -116,11 +116,11 @@ def _visualize(target):
_showLayer(target)
elif objectHelpers.isKindOfClass(target, 'NSData'):
if _dataIsImage(target):
_showImage('(id)[UIImage imageWithData:' + target + ']');
_showImage('(id)[UIImage imageWithData:' + target + ']')
elif _dataIsString(target):
lldb.debugger.HandleCommand('po (NSString*)[[NSString alloc] initWithData:' + target + ' encoding:4]')
else:
print 'Data isn\'t an image and isn\'t a string.';
print 'Data isn\'t an image and isn\'t a string.'
else:
print '{} isn\'t supported. You can visualize UIImage, CGImageRef, UIView, CALayer or NSData.'.format(objectHelpers.className(target))

Expand Down
Loading