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 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 _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 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 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 iOS 10 and higher if fb.evaluateBooleanExpression( "[UIView respondsToSelector:@selector(_accessibilityElementsAndContainersDescendingFromViews:options:sorted:)]" # noqa B950 ): accessibilityElements = fb.evaluateObjectExpression( "[UIView _accessibilityElementsAndContainersDescendingFromViews:@[(id)%s] options:0 sorted:NO]" # noqa B950 % view) else: accessibilityElements = fb.evaluateObjectExpression( "[[[UIApplication sharedApplication] keyWindow] _accessibilityElementsInContainer:0 topLevel:%s includeKB:0]" # noqa B950 % 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 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 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 _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 = 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 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 firstSubviewOfView(view): subviews = subviewsOfView(view) numViews = fb.evaluateIntegerExpression('[(id)' + subviews + ' count]') if numViews == 0: return None else: return fb.evaluateObjectExpression('[' + subviews + ' objectAtIndex:0]')
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): 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 run(self, arguments, options): # It's a good habit to explicitly cast the type of all return # values and arguments. LLDB can't always find them on its own. subviews = fb.evaluateInputExpression(arguments[0]) # subviews = subviewsOfView(selfView) view = fb.evaluateInputExpression(arguments[1]) index = fb.evaluateIntegerExpression('[[' + subviews + ' subviews] indexOfObject:' + view + ']') # index = fb.evaluateIntegerExpression('[(id)' + subviews + '.subviews indexOfObject:' + view + ']') # index = fb.evaluateExpression('[(UIView *)%s.subviews indexOfObject:(UIView *)%s]' % (subviews, view)) # pdb.set_trace() print ('index: %d' % index)
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 = fb.evaluateIntegerExpression('(int)[(id)%s count]' % subviews) if subviewsCount > 0: for i in range(0, subviewsCount): subview = fb.evaluateExpression('(id)[%s objectAtIndex:%i]' % (subviews, i)) setBorderOnAmbiguousViewRecursive(subview, width, color)
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 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 _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 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())