Skip to content

Commit

Permalink
Merge pull request #1 from facebook/master
Browse files Browse the repository at this point in the history
Merge
  • Loading branch information
longv2go committed Jan 28, 2015
2 parents 708f6e5 + 96e0a64 commit 52c8500
Show file tree
Hide file tree
Showing 16 changed files with 123 additions and 99 deletions.
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

0 comments on commit 52c8500

Please sign in to comment.