def visualizeRect(rect, referenceView): refView = fb.evaluateObjectExpression(referenceView) targetRectExpression = "(CGRect)[(UIView*){:s} convertRect:(CGRect){:s} toView:(UIView*)[{:s} window]]".format(refView, rect, refView) overlayView = fb.evaluateObjectExpression("(UIView*)[[UIView alloc] initWithFrame:(CGRect){:s}]".format(targetRectExpression)) lldb.debugger.HandleCommand("exp (void)[(UIView*)[{} window] addSubview:(UIView*){}]".format(refView, overlayView)) lldb.debugger.HandleCommand("exp (void)[(UIView*){} setUserInteractionEnabled:NO]".format(overlayView)) lldb.debugger.HandleCommand("border {:s}".format(overlayView)) lldb.debugger.HandleCommand("caflush") print "Visualized {:s} using {}".format(rect, overlayView)
def visualizePoint(point, referenceView): refView = fb.evaluateObjectExpression(referenceView) targetPointExpression = "(CGPoint)[(UIView*){:s} convertPoint:(CGPoint){:s} toView:(UIView*)[{:s} window]]".format(refView, point, refView) viewFrame = "(CGRect)CGRectMake(0, 0, 4, 4)" overlayView = fb.evaluateObjectExpression("(UIView*)[[UIView alloc] initWithFrame:{:s}]".format(viewFrame)) lldb.debugger.HandleCommand("exp (void)[(UIView*){:s} setCenter:(CGPoint){:s}]".format(overlayView, targetPointExpression)) lldb.debugger.HandleCommand("exp (void)[(UIView*)[{} window] addSubview:(UIView*){}]".format(refView, overlayView)) lldb.debugger.HandleCommand("exp (void)[(UIView*){} setUserInteractionEnabled:NO]".format(overlayView)) lldb.debugger.HandleCommand("border {:s}".format(overlayView)) print "Visualized {:s} using {}".format(point, overlayView)
def run(self, arguments, options): control = fb.evaluateInputExpression(arguments[0]) targets = fb.evaluateObjectExpression('[[{control} allTargets] allObjects]'.format(control=control)) targetCount = fb.evaluateIntegerExpression('[{targets} count]'.format(targets=targets)) for index in range(0, targetCount): target = fb.evaluateObjectExpression('[{targets} objectAtIndex:{index}]'.format(targets=targets, index=index)) actions = fb.evaluateObjectExpression('[{control} actionsForTarget:{target} forControlEvent:0]'.format(control=control, target=target)) targetDescription = fb.evaluateExpressionValue('(id){target}'.format(target=target)).GetObjectDescription() actionsDescription = fb.evaluateExpressionValue('(id)[{actions} componentsJoinedByString:@", "]'.format(actions=actions)).GetObjectDescription() print ('{target}: {actions}'.format(target=targetDescription, actions=actionsDescription))
def run(self, arguments, options): control = arguments[0] targets = fb.evaluateObjectExpression('[[{control} allTargets] allObjects]'.format(control=control)) targetCount = fb.evaluateIntegerExpression('[{targets} count]'.format(targets=targets)) for index in range(0, targetCount): target = fb.evaluateObjectExpression('[{targets} objectAtIndex:{index}]'.format(targets=targets, index=index)) actions = fb.evaluateObjectExpression('[{control} actionsForTarget:{target} forControlEvent:0]'.format(control=control, target=target)) targetDescription = fb.evaluateExpressionValue('(id){target}'.format(target=target)).GetObjectDescription() actionsDescription = fb.evaluateExpressionValue('(id)[{actions} componentsJoinedByString:@", "]'.format(actions=actions)).GetObjectDescription() print '{target}: {actions}'.format(target=targetDescription, actions=actionsDescription)
def printAccessibilityHierarchy(view, indent = 0): a11yLabel = accessibilityLabel(view) classDesc = objHelpers.className(view) indentString = ' | ' * indent #if we don't have any accessibility string - we should have some children if int(a11yLabel.GetValue(), 16) == 0: print indentString + ('{} {}'.format(classDesc, view)) #We call private method that gives back all visible accessibility children for view accessibilityElements = fb.evaluateObjectExpression('[[[UIApplication sharedApplication] keyWindow] _accessibilityElementsInContainer:0 topLevel:%s includeKB:0]' % view) accessibilityElementsCount = fb.evaluateIntegerExpression('(int)[%s count]' % accessibilityElements) for index in range(0, accessibilityElementsCount): subview = fb.evaluateObjectExpression('[%s objectAtIndex:%i]' % (accessibilityElements, index)) printAccessibilityHierarchy(subview, indent + 1) else: print indentString + ('({} {}) {}'.format(classDesc, view, a11yLabel.GetObjectDescription()))
def run(self, arguments, options): objectToPrint = arguments[0] pretty = 1 if options.plain is None else 0 jsonData = fb.evaluateObjectExpression('[NSJSONSerialization dataWithJSONObject:{} options:{} error:nil]'.format(objectToPrint, pretty)) jsonString = fb.evaluateExpressionValue('(NSString*)[[NSString alloc] initWithData:{} encoding:4]'.format(jsonData)).GetObjectDescription() print(jsonString)
def _recursiveViewControllerDescriptionWithPrefixAndChildPrefix( vc, string, prefix, childPrefix): s = '%s%s%s\n' % (prefix, '' if prefix == '' else ' ', _viewControllerDescription(vc)) nextPrefix = childPrefix + ' |' numChildViewControllers = fb.evaluateIntegerExpression( '(int)[(id)[%s childViewControllers] count]' % (vc)) childViewControllers = fb.evaluateExpression( '(id)[%s childViewControllers]' % (vc)) for i in range(0, numChildViewControllers): viewController = fb.evaluateExpression( '(id)[(id)[%s childViewControllers] objectAtIndex:%d]' % (vc, i)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix( viewController, string, nextPrefix, nextPrefix) isModal = fb.evaluateBooleanExpression( '%s != nil && ((id)[(id)[(id)%s presentedViewController] presentingViewController]) == %s' % (vc, vc, vc)) if isModal: modalVC = fb.evaluateObjectExpression( '(id)[(id)%s presentedViewController]' % (vc)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix( modalVC, string, childPrefix + ' *M', nextPrefix) s += '\n// \'*M\' means the view controller is presented modally.' return string + s
def printAccessibilityHierarchy(view, indent = 0): a11yLabel = accessibilityLabel(view) classDesc = objHelpers.className(view) indentString = ' | ' * indent #if we don't have any accessibility string - we should have some children if int(a11yLabel.GetValue(), 16) == 0: print indentString + ('{} {}'.format(classDesc, view)) #We call private method that gives back all visible accessibility children for view accessibilityElements = fb.evaluateObjectExpression('[[[UIApplication sharedApplication] keyWindow] _accessibilityElementsInContainer:0 topLevel:%s includeKB:0]' % view) accessibilityElementsCount = int(fb.evaluateExpression('(int)[%s count]' % accessibilityElements)) for index in range(0, accessibilityElementsCount): subview = fb.evaluateObjectExpression('[%s objectAtIndex:%i]' % (accessibilityElements, index)) printAccessibilityHierarchy(subview, indent + 1) else: print indentString + ('({} {}) {}'.format(classDesc, view, a11yLabel.GetObjectDescription()))
def run(self, arguments, options): object = fb.evaluateObjectExpression(arguments[0]) objectClass = fb.evaluateExpressionValue( '(id)[(id)(' + object + ') class]').GetObjectDescription() command = 'p *(({} *)((id){}))'.format(objectClass, object) lldb.debugger.HandleCommand(command)
def run(self, arguments, options): commandForObject, ivarName = arguments objectAddress = int(fb.evaluateObjectExpression(commandForObject), 0) ivarOffsetCommand = '(ptrdiff_t)ivar_getOffset((void*)object_getInstanceVariable((id){}, "{}", 0))'.format( objectAddress, ivarName) ivarOffset = int(fb.evaluateExpression(ivarOffsetCommand), 0) # 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((void*)class_getInstanceVariable((Class)object_getClass((id){}), "{}"));' '(char *)NSGetSizeAndAlignment(typeEncoding, &size, 0);' 'size').format(objectAddress, ivarName) ivarSize = int(fb.evaluateExpression(ivarSizeCommand), 0) error = lldb.SBError() watchpoint = lldb.debugger.GetSelectedTarget().WatchAddress( objectAddress + ivarOffset, ivarSize, False, True, error) if error.Success(): print 'Remember to delete the watchpoint using: watchpoint delete {}'.format( watchpoint.GetID()) else: print 'Could not create the watchpoint: {}'.format( error.GetCString())
def run(self, arguments, options): objectToPrint = fb.evaluateInputExpression(arguments[0]) pretty = 1 if options.plain is None else 0 jsonData = fb.evaluateObjectExpression('[NSJSONSerialization dataWithJSONObject:(id){} options:{} error:nil]'.format(objectToPrint, pretty)) jsonString = fb.evaluateExpressionValue('(NSString*)[[NSString alloc] initWithData:(id){} encoding:4]'.format(jsonData)).GetObjectDescription() print jsonString
def _recursiveViewControllerDescriptionWithPrefixAndChildPrefix( vc, string, prefix, childPrefix): isMac = runtimeHelpers.isMacintoshArch() s = "%s%s%s\n" % ( prefix, "" if prefix == "" else " ", _viewControllerDescription(vc), ) nextPrefix = childPrefix + " |" numChildViewControllers = fb.evaluateIntegerExpression( "(int)[(id)[%s childViewControllers] count]" % (vc)) for i in range(0, numChildViewControllers): viewController = fb.evaluateExpression( "(id)[(id)[%s childViewControllers] objectAtIndex:%d]" % (vc, i)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix( viewController, string, nextPrefix, nextPrefix) if not isMac: isModal = fb.evaluateBooleanExpression( "%s != nil && ((id)[(id)[(id)%s presentedViewController] presentingViewController]) == %s" # noqa B950 % (vc, vc, vc)) if isModal: modalVC = fb.evaluateObjectExpression( "(id)[(id)%s presentedViewController]" % (vc)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix( modalVC, string, childPrefix + " *M", nextPrefix) s += "\n// '*M' means the view controller is presented modally." return string + s
def _recursiveViewControllerDescriptionWithPrefixAndChildPrefix(vc, string, prefix, childPrefix): isMac = runtimeHelpers.isMacintoshArch() s = "%s%s%s\n" % (prefix, "" if prefix == "" else " ", _viewControllerDescription(vc)) nextPrefix = childPrefix + " |" numChildViewControllers = fb.evaluateIntegerExpression("(int)[(id)[%s childViewControllers] count]" % (vc)) childViewControllers = fb.evaluateExpression("(id)[%s childViewControllers]" % (vc)) for i in range(0, numChildViewControllers): viewController = fb.evaluateExpression("(id)[(id)[%s childViewControllers] objectAtIndex:%d]" % (vc, i)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix(viewController, string, nextPrefix, nextPrefix) if not isMac: isModal = fb.evaluateBooleanExpression( "%s != nil && ((id)[(id)[(id)%s presentedViewController] presentingViewController]) == %s" % (vc, vc, vc) ) if isModal: modalVC = fb.evaluateObjectExpression("(id)[(id)%s presentedViewController]" % (vc)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix( modalVC, string, childPrefix + " *M", nextPrefix ) s += "\n// '*M' means the view controller is presented modally." return string + s
def run(self, arguments, options): request = arguments[0] HTTPHeaderSring = '' HTTPMethod = fb.evaluateExpressionValue('(id)[{} HTTPMethod]'.format(request)).GetObjectDescription() URL = fb.evaluateExpressionValue('(id)[{} URL]'.format(request)).GetObjectDescription() timeout = fb.evaluateExpression('(NSTimeInterval)[{} timeoutInterval]'.format(request)) HTTPHeaders = fb.evaluateObjectExpression('(id)[{} allHTTPHeaderFields]'.format(request)) HTTPHeadersCount = fb.evaluateIntegerExpression('[{} count]'.format(HTTPHeaders)) allHTTPKeys = fb.evaluateObjectExpression('[{} allKeys]'.format(HTTPHeaders)) for index in range(0, HTTPHeadersCount): key = fb.evaluateObjectExpression('[{} objectAtIndex:{}]'.format(allHTTPKeys, index)) keyDescription = fb.evaluateExpressionValue('(id){}'.format(key)).GetObjectDescription() value = fb.evaluateExpressionValue('(id)[(id){} objectForKey:{}]'.format(HTTPHeaders, key)).GetObjectDescription() if len(HTTPHeaderSring) > 0: HTTPHeaderSring += ' ' HTTPHeaderSring += '-H "{}: {}"'.format(keyDescription, value) HTTPData = fb.evaluateObjectExpression('[{} HTTPBody]'.format(request)) dataFile = None dataAsString = None if fb.evaluateIntegerExpression('[{} length]'.format(HTTPData)) > 0: if options.embed: if fb.evaluateIntegerExpression('[{} respondsToSelector:@selector(base64EncodedStringWithOptions:)]'.format(HTTPData)): dataAsString = fb.evaluateExpressionValue('(id)[(id){} base64EncodedStringWithOptions:0]'.format(HTTPData)).GetObjectDescription() else : print('This version of OS doesn\'t supports base64 data encoding') return False elif not runtimeHelpers.isIOSDevice(): dataFile = self.generateTmpFilePath() if not fb.evaluateBooleanExpression('(BOOL)[{} writeToFile:@"{}" atomically:NO]'.format(HTTPData, dataFile)): print('Can\'t write data to file {}'.format(dataFile)) return False else: print('HTTPBody data for iOS Device is supported only with "--embed-data" flag') return False commandString = '' if dataAsString is not None and len(dataAsString) > 0: dataFile = self.generateTmpFilePath() commandString += 'echo "{}" | base64 -D -o "{}" && '.format(dataAsString, dataFile) commandString += 'curl -X {} --connect-timeout {}'.format(HTTPMethod, timeout) if len(HTTPHeaderSring) > 0: commandString += ' ' + HTTPHeaderSring if dataFile is not None: commandString += ' --data-binary @"{}"'.format(dataFile) commandString += ' "{}"'.format(URL) print(commandString)
def run(self, arguments, options): request = fb.evaluateInputExpression(arguments[0]) HTTPHeaderSring = '' HTTPMethod = fb.evaluateExpressionValue('(id)[{} HTTPMethod]'.format(request)).GetObjectDescription() URL = fb.evaluateExpressionValue('(id)[{} URL]'.format(request)).GetObjectDescription() timeout = fb.evaluateExpression('(NSTimeInterval)[{} timeoutInterval]'.format(request)) HTTPHeaders = fb.evaluateObjectExpression('(id)[{} allHTTPHeaderFields]'.format(request)) HTTPHeadersCount = fb.evaluateIntegerExpression('[{} count]'.format(HTTPHeaders)) allHTTPKeys = fb.evaluateObjectExpression('[{} allKeys]'.format(HTTPHeaders)) for index in range(0, HTTPHeadersCount): key = fb.evaluateObjectExpression('[{} objectAtIndex:{}]'.format(allHTTPKeys, index)) keyDescription = fb.evaluateExpressionValue('(id){}'.format(key)).GetObjectDescription() value = fb.evaluateExpressionValue('(id)[(id){} objectForKey:{}]'.format(HTTPHeaders, key)).GetObjectDescription() if len(HTTPHeaderSring) > 0: HTTPHeaderSring += ' ' HTTPHeaderSring += '-H "{}: {}"'.format(keyDescription, value) HTTPData = fb.evaluateObjectExpression('[{} HTTPBody]'.format(request)) dataFile = None dataAsString = None if fb.evaluateIntegerExpression('[{} length]'.format(HTTPData)) > 0: if options.embed: if fb.evaluateIntegerExpression('[{} respondsToSelector:@selector(base64EncodedStringWithOptions:)]'.format(HTTPData)): dataAsString = fb.evaluateExpressionValue('(id)[(id){} base64EncodedStringWithOptions:0]'.format(HTTPData)).GetObjectDescription() else : print 'This version of OS doesn\'t supports base64 data encoding' return False elif not runtimeHelpers.isIOSDevice(): dataFile = self.generateTmpFilePath() if not fb.evaluateBooleanExpression('(BOOL)[{} writeToFile:@"{}" atomically:NO]'.format(HTTPData, dataFile)): print 'Can\'t write data to file {}'.format(dataFile) return False else: print 'HTTPBody data for iOS Device is supported only with "--embed-data" flag' return False commandString = '' if dataAsString is not None and len(dataAsString) > 0: dataFile = self.generateTmpFilePath() commandString += 'echo "{}" | base64 -D -o "{}" && '.format(dataAsString, dataFile) commandString += 'curl -X {} --connect-timeout {}'.format(HTTPMethod, timeout) if len(HTTPHeaderSring) > 0: commandString += ' ' + HTTPHeaderSring if dataFile is not None: commandString += ' --data-binary @"{}"'.format(dataFile) commandString += ' "{}"'.format(URL) print commandString
def visualizeRect(rect, referenceView): refView = fb.evaluateObjectExpression(referenceView) targetRectExpression = "(CGRect)[(UIView*){:s} convertRect:(CGRect){:s} toView:(UIView*)[{:s} window]]".format( refView, rect, refView) overlayView = fb.evaluateObjectExpression( "(UIView*)[[UIView alloc] initWithFrame:(CGRect){:s}]".format( targetRectExpression)) lldb.debugger.HandleCommand( "exp (void)[(UIView*)[{} window] addSubview:(UIView*){}]".format( refView, overlayView)) lldb.debugger.HandleCommand( "exp (void)[(UIView*){} setUserInteractionEnabled:NO]".format( overlayView)) lldb.debugger.HandleCommand("border {:s}".format(overlayView)) lldb.debugger.HandleCommand("caflush") print "Visualized {:s} using {}".format(rect, overlayView)
def run(self, arguments, options): #Convert to NSObject first to allow for objc runtime to process it objectToPrint = fb.evaluateInputExpression('{obj} as NSObject'.format(obj=arguments[0])) pretty = 1 if options.plain is None else 0 jsonData = fb.evaluateObjectExpression('[NSJSONSerialization dataWithJSONObject:(NSObject*){} options:{} error:nil]'.format(objectToPrint, pretty)) jsonString = fb.evaluateExpressionValue('(NSString*)[[NSString alloc] initWithData:(NSObject*){} encoding:4]'.format(jsonData)).GetObjectDescription() print jsonString
def firstSubviewOfView(view): subviews = subviewsOfView(view) numViews = fb.evaluateIntegerExpression('[(id)' + subviews + ' count]') if numViews == 0: return None else: return fb.evaluateObjectExpression('[' + subviews + ' objectAtIndex:0]')
def run(self, arguments, options): object = fb.evaluateObjectExpression(arguments[0]) isHidden = fb.evaluateBooleanExpression('[' + object + ' isHidden]') shouldHide = not isHidden for x in range(0, 2): viewHelpers.setViewHidden(object, shouldHide) viewHelpers.setViewHidden(object, isHidden)
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) print fb.describeObject('[{} valueForKeyPath:@"{}"]'.format(object, keypath))
def accessibilityElements(view): if fb.evaluateBooleanExpression('[UIView instancesRespondToSelector:@selector(accessibilityElements)]'): a11yElements = fb.evaluateExpression('(id)[%s accessibilityElements]' % view, False) if int(a11yElements, 16) != 0: return a11yElements if fb.evaluateBooleanExpression('[%s respondsToSelector:@selector(_accessibleSubviews)]' % view): return fb.evaluateExpression('(id)[%s _accessibleSubviews]' % (view), False) else: return fb.evaluateObjectExpression('[[[UIApplication sharedApplication] keyWindow] _accessibilityElementsInContainer:0 topLevel:%s includeKB:0]' % view)
def firstSubviewOfView(view): subviews = subviewsOfView(view) numViews = fb.evaluateIntegerExpression("[(id)" + subviews + " count]") if numViews == 0: return None else: return fb.evaluateObjectExpression("[" + subviews + " objectAtIndex:0]")
def visualizePoint(point, referenceView): refView = fb.evaluateObjectExpression(referenceView) targetPointExpression = "(CGPoint)[(UIView*){:s} convertPoint:(CGPoint){:s} toView:(UIView*)[{:s} window]]".format( refView, point, refView) viewFrame = "(CGRect)CGRectMake(0, 0, 4, 4)" overlayView = fb.evaluateObjectExpression( "(UIView*)[[UIView alloc] initWithFrame:{:s}]".format(viewFrame)) lldb.debugger.HandleCommand( "exp (void)[(UIView*){:s} setCenter:(CGPoint){:s}]".format( overlayView, targetPointExpression)) lldb.debugger.HandleCommand( "exp (void)[(UIView*)[{} window] addSubview:(UIView*){}]".format( refView, overlayView)) lldb.debugger.HandleCommand( "exp (void)[(UIView*){} setUserInteractionEnabled:NO]".format( overlayView)) lldb.debugger.HandleCommand("border {:s}".format(overlayView)) print "Visualized {:s} using {}".format(point, overlayView)
def nextResponder(object): command = '[((id){}) nextResponder]'.format(object) nextResponder = fb.evaluateObjectExpression(command) try: if int(nextResponder, 0): return nextResponder else: return None except: return None
def accessibilityGrepHierarchy(self, view, needle): a11yLabel = accessibilityLabel(view) #if we don't have any accessibility string - we should have some children if int(a11yLabel.GetValue(), 16) == 0: #We call private method that gives back all visible accessibility children for view accessibilityElements = fb.evaluateObjectExpression('[[[UIApplication sharedApplication] keyWindow] _accessibilityElementsInContainer:0 topLevel:%s includeKB:0]' % view) accessibilityElementsCount = fb.evaluateIntegerExpression('[%s count]' % accessibilityElements) for index in range(0, accessibilityElementsCount): subview = fb.evaluateObjectExpression('[%s objectAtIndex:%i]' % (accessibilityElements, index)) self.accessibilityGrepHierarchy(subview, needle) elif re.match(r'.*' + needle + '.*', a11yLabel.GetObjectDescription(), re.IGNORECASE): classDesc = objHelpers.className(view) print('({} {}) {}'.format(classDesc, view, a11yLabel.GetObjectDescription())) #First element that is found is copied to clipboard if not self.foundElement: self.foundElement = True cmd = 'echo %s | tr -d "\n" | pbcopy' % view os.system(cmd)
def run(self, arguments, options): commandForObject, ivarName = arguments object = fb.evaluateObjectExpression(commandForObject) objectClass = fb.evaluateExpressionValue('(id)[(' + object + ') class]').GetObjectDescription() 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))
def nthSiblingOfView(view, n): subviews = subviewsOfView(superviewOfView(view)) numViews = fb.evaluateIntegerExpression('[(id)' + subviews + ' count]') idx = fb.evaluateIntegerExpression('[(id)' + subviews + ' indexOfObject:' + view + ']') newIdx = idx + n while newIdx < 0: newIdx += numViews newIdx = newIdx % numViews return fb.evaluateObjectExpression('[(id)' + subviews + ' objectAtIndex:' + str(newIdx) + ']')
def run(self, arguments, options): object = fb.evaluateObjectExpression(arguments[0]) if options.appleWay: if fb.evaluateBooleanExpression('[{} respondsToSelector:@selector(_ivarDescription)]'.format(object)): command = 'po [{} _ivarDescription]'.format(object) else: print 'Sorry, but it seems Apple dumped the _ivarDescription method' return else: objectClass = fb.evaluateExpressionValue('(id)[(id)(' + object + ') class]').GetObjectDescription() command = 'p *(({} *)((id){}))'.format(objectClass, object) lldb.debugger.HandleCommand(command)
def run(self, arguments, options): commandForObject = arguments[0] object = fb.evaluateObjectExpression(commandForObject) fb.evaluateExpressionValue('unsigned int $fblldb_ivar_count = 0', False) fb.evaluateExpressionValue('intptr_t *$fblldb_ivars = (intptr_t *)class_copyIvarList((Class)object_getClass({}), &$fblldb_ivar_count)'.format(object), False) ivarCount = int(fb.evaluateExpression('$fblldb_ivar_count')) for i in range(0, ivarCount): # TODO Unsure how to easily read the string properly, so just getting a summary and removing the quotes. ivarName = fb.evaluateExpressionValue('(char *)ivar_getName((void *)$fblldb_ivars[{}])'.format(i)).GetSummary()[1:-1] print '{} -> '.format(ivarName), FBPrintInstanceVariable().run([commandForObject, ivarName], options)
def run(self, arguments, options): # pdb.set_trace() object = lldb.SBCommandReturnObject() coreName = fb.evaluateExpression('((' + arguments[0] + ' *)[CoreManager getCore:[' + arguments[0] + ' class]])') result = fb.evaluateObjectExpression('(id)[' + coreName + ' %s]' % arguments[1]) print('result: {}'.format(result)) print('<{}: {}>'.format(arguments[0], coreName)) lldb.debugger.HandleCommand('po [(%s *)%s %s]' % (arguments[0], coreName, arguments[1]))
def run(self, arguments, options): commandForObject, ivarName = arguments object = fb.evaluateObjectExpression(commandForObject) objectClass = fb.evaluateExpressionValue("(id)[(" + object + ") class]").GetObjectDescription() 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))
def nthSiblingOfView(view, n): subviews = subviewsOfView(superviewOfView(view)) numViews = fb.evaluateIntegerExpression("[(id)" + subviews + " count]") idx = fb.evaluateIntegerExpression("[(id)" + subviews + " indexOfObject:" + view + "]") newIdx = idx + n while newIdx < 0: newIdx += numViews newIdx = newIdx % numViews return fb.evaluateObjectExpression("[(id)" + subviews + " objectAtIndex:" + str(newIdx) + "]")
def run(self, arguments, options): commandForObject, ivarName = arguments object = fb.evaluateObjectExpression(commandForObject) valueVariableName = '$fblldb_{}_value'.format(ivarName) fb.evaluateExpressionValue('void *{} = NULL'.format(valueVariableName), False) ivarTypeCommand = '((char *)ivar_getTypeEncoding((void *)object_getInstanceVariable((id){}, \"{}\", &{})))[0]'.format(object, ivarName, valueVariableName) ivarTypeEncodingFirstChar = fb.evaluateExpression(ivarTypeCommand) printCommand = 'po' if ('@' in ivarTypeEncodingFirstChar) else 'p' lldb.debugger.HandleCommand('{} {}'.format(printCommand, valueVariableName)) fb.evaluateExpressionValue('{} = NULL'.format(valueVariableName))
def printAccessibilityIdentifiersHierarchy(view, indent = 0): a11yIdentifier = accessibilityIdentifier(view) classDesc = objHelpers.className(view) indentString = ' | ' * indent #if we don't have any accessibility identifier - we should have some children if int(a11yIdentifier.GetValue(), 16) == 0: print indentString + ('{} {}'.format(classDesc, view)) #We call private method that gives back all visible accessibility children for view a11yElements = accessibilityElements(view) accessibilityElementsCount = int(fb.evaluateExpression('(int)[%s count]' % a11yElements)) for index in range(0, accessibilityElementsCount): subview = fb.evaluateObjectExpression('[%s objectAtIndex:%i]' % (a11yElements, index)) printAccessibilityIdentifiersHierarchy(subview, indent + 1) else: print indentString + ('({} {}) {}'.format(classDesc, view, a11yIdentifier.GetObjectDescription()))
def _recursiveViewControllerDescriptionWithPrefixAndChildPrefix(vc, string, prefix, childPrefix): s = '%s%s%s\n' % (prefix, '' if prefix == '' else ' ', _viewControllerDescription(vc)) nextPrefix = childPrefix + ' |' numChildViewControllers = fb.evaluateIntegerExpression('(int)[(id)[%s childViewControllers] count]' % (vc)) childViewControllers = fb.evaluateExpression('(id)[%s childViewControllers]' % (vc)) for i in range(0, numChildViewControllers): viewController = fb.evaluateExpression('(id)[(id)[%s childViewControllers] objectAtIndex:%d]' % (vc, i)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix(viewController, string, nextPrefix, nextPrefix) isModal = fb.evaluateBooleanExpression('((id)[(id)[(id)%s presentedViewController] presentingViewController]) == %s' % (vc, vc)) if isModal: modalVC = fb.evaluateObjectExpression('(id)[(id)%s presentedViewController]' % (vc)) s += _recursiveViewControllerDescriptionWithPrefixAndChildPrefix(modalVC, string, childPrefix + ' *M' , nextPrefix) s += '\n// \'*M\' means the view controller is presented modally.' return string + s
def printAccessibilityHierarchy(view, indent=0): a11yLabel = accessibilityLabel(view) classDesc = objHelpers.className(view) indentString = " | " * indent # if we don't have any accessibility string - we should have some children if int(a11yLabel.GetValue(), 16) == 0: print(indentString + ("{} {}".format(classDesc, view))) # We call private method that gives back all visible accessibility children # for view a11yElements = accessibilityElements(view) accessibilityElementsCount = int( fb.evaluateExpression("(int)[%s count]" % a11yElements)) for index in range(0, accessibilityElementsCount): subview = fb.evaluateObjectExpression("[%s objectAtIndex:%i]" % (a11yElements, index)) printAccessibilityHierarchy(subview, indent + 1) else: print(indentString + ("({} {}) {}".format( classDesc, view, a11yLabel.GetObjectDescription())))
def _showImage(commandForImage): imageDirectory = '/tmp/xcode_debug_images/' imageName = time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime()) + ".png" imagePath = imageDirectory + imageName try: os.makedirs(imageDirectory) except OSError as e: if e.errno == errno.EEXIST and os.path.isdir(imageDirectory): pass else: raise imageDataAddress = fb.evaluateObjectExpression( 'UIImagePNGRepresentation((id)' + commandForImage + ')') imageBytesStartAddress = fb.evaluateExpression('(void *)[(id)' + imageDataAddress + ' bytes]') imageBytesLength = fb.evaluateExpression('(NSUInteger)[(id)' + imageDataAddress + ' length]') 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: imgFile = open(imagePath, 'wb') imgFile.write(mem) imgFile.close() os.system('open ' + imagePath)
def run(self, arguments, options): commandForObject, ivarName = arguments objectAddress = int(fb.evaluateObjectExpression(commandForObject), 0) ivarOffsetCommand = '(ptrdiff_t)ivar_getOffset((Ivar)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 *)NSGetSizeAndAlignment(typeEncoding, &size, 0);' 'size').format(objectAddress, ivarName) ivarSize = int(fb.evaluateExpression(ivarSizeCommand), 0) error = lldb.SBError() watchpoint = lldb.debugger.GetSelectedTarget().WatchAddress(objectAddress + ivarOffset, ivarSize, False, True, error) if error.Success(): print 'Remember to delete the watchpoint using: watchpoint delete {}'.format(watchpoint.GetID()) else: print 'Could not create the watchpoint: {}'.format(error.GetCString())
def _showImage(commandForImage): imageDirectory = '/tmp/xcode_debug_images/' imageName = time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime()) + ".png" imagePath = imageDirectory + imageName try: os.makedirs(imageDirectory) except OSError as e: if e.errno == errno.EEXIST and os.path.isdir(imageDirectory): pass else: raise imageDataAddress = fb.evaluateObjectExpression('UIImagePNGRepresentation((id)' + commandForImage + ')') imageBytesStartAddress = fb.evaluateExpression('(void *)[(id)' + imageDataAddress + ' bytes]') imageBytesLength = fb.evaluateExpression('(NSUInteger)[(id)' + imageDataAddress + ' length]') 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: imgFile = open(imagePath, 'wb') imgFile.write(mem) imgFile.close() os.system('open ' + imagePath)
def subviewsOfView(view): return fb.evaluateObjectExpression('[' + view + ' subviews]')
def run(self, arguments, options): object = fb.evaluateObjectExpression(arguments[0]) objectClass = fb.evaluateExpressionValue("(id)[(id)(" + object + ") class]").GetObjectDescription() command = "p *(({} *)((id){}))".format(objectClass, object) lldb.debugger.HandleCommand(command)
def rootView(): return fb.evaluateObjectExpression( '[[UIApplication sharedApplication] keyWindow]')
def setTextInView(view, text): fb.evaluateObjectExpression('[%s setText:@"%s"]' % (view, text)) viewHelpers.flushCoreAnimationTransaction()
def run(self, arguments, options): print '\nUse the following and (q) to quit.\n(w) move to superview\n(s) move to first subview\n(a) move to previous sibling\n(d) move to next sibling\n(p) print the hierarchy\n' object = fb.evaluateObjectExpression(arguments[0]) walker = FlickerWalker(object) walker.run()
def viewControllerRecursiveDescription(vc): return _recursiveViewControllerDescriptionWithPrefixAndChildPrefix(fb.evaluateObjectExpression(vc), '', '', '')
def run(self, arguments, options): expression = arguments[0] match = re.match(r'([-+])*\[(.*) (.*)\]', expression) if not match: print 'Failed to parse expression. Do you even Objective-C?!' return expressionForSelf = objc.functionPreambleExpressionForSelf() if not expressionForSelf: 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) methodIsClassMethod = (methodTypeCharacter == '+') if not methodIsClassMethod: # The default is instance method, and methodTypeCharacter may not actually be '-'. methodTypeCharacter = '-' targetIsClass = False targetObject = fb.evaluateObjectExpression('({})'.format(classNameOrExpression), False) if not targetObject: # If the expression didn't yield anything then it's likely a class. Assume it is. # We will check again that the class does actually exist anyway. targetIsClass = True targetObject = fb.evaluateObjectExpression('[{} class]'.format(classNameOrExpression), False) targetClass = fb.evaluateObjectExpression('[{} class]'.format(targetObject), False) if not targetClass or int(targetClass, 0) == 0: print 'Couldn\'t find a class from the expression "{}". Did you typo?'.format(classNameOrExpression) return if methodIsClassMethod: targetClass = objc.object_getClass(targetClass) found = False nextClass = targetClass while not found and int(nextClass, 0) > 0: if classItselfImplementsSelector(nextClass, selector): found = True else: nextClass = objc.class_getSuperclass(nextClass) if not found: print 'There doesn\'t seem to be an implementation of {} in the class hierarchy. Made a boo boo with the selector name?'.format(selector) return breakpointClassName = objc.class_getName(nextClass) breakpointFullName = '{}[{} {}]'.format(methodTypeCharacter, breakpointClassName, selector) breakpointCondition = None if targetIsClass: breakpointCondition = '(void*)object_getClass({}) == {}'.format(expressionForSelf, targetClass) else: breakpointCondition = '(void*){} == {}'.format(expressionForSelf, targetObject) print 'Setting a breakpoint at {} with condition {}'.format(breakpointFullName, breakpointCondition) lldb.debugger.HandleCommand('breakpoint set --fullname "{}" --condition "{}"'.format(breakpointFullName, breakpointCondition))
def subviewsOfView(view): return fb.evaluateObjectExpression('[%s subviews]' % view)
def subviewAtIndex(views, index): return fb.evaluateObjectExpression('[%s objectAtIndex:%i]' % (views, index))
def superviewOfView(view): superview = fb.evaluateObjectExpression('[' + view + ' superview]') if int(superview, 16) == 0: return None return superview