def unmaskView(viewOrLayer): window = fb.evaluateExpression( "(UIWindow *)[[UIApplication sharedApplication] keyWindow]") mask = fb.evaluateExpression("(UIView *)[%s viewWithTag:(NSInteger)%s]" % (window, viewOrLayer)) fb.evaluateEffect("[%s removeFromSuperview]" % mask) flushCoreAnimationTransaction()
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 prettyPrintInvocation(frame, invocation): object = fb.evaluateExpression("(id)[(id)" + invocation + " target]") description = fb.evaluateExpressionValue( "(id)" + invocation).GetObjectDescription() argDescriptions = description.splitlines(True)[4:] print("NSInvocation: " + invocation) print("self: " + fb.evaluateExpression("(id)" + object)) if len(argDescriptions) > 0: print("\n" + str(len(argDescriptions)) + " Arguments:" if len(argDescriptions) > 1 else "\nArgument:") index = 2 for argDescription in argDescriptions: s = re.sub(r"argument [0-9]+: ", "", argDescription) address = findArgAdressAtIndexFromStackFrame(frame, index) encoding = s.split(" ")[0] description = " ".join(s.split(" ")[1:]) readableString = argumentAsString(frame, address, encoding) if readableString: print(readableString) else: if encoding[0] == "{": encoding = encoding[1:] print((hex(address) + ", address of " + encoding + " " + description).strip()) index += 1
def _inheritanceHierarchy(instanceOfAClass): instanceAddress = fb.evaluateExpression(instanceOfAClass) instanceClass = fb.evaluateExpression("(id)[(id)" + instanceAddress + " class]") while int(instanceClass, 16): yield fb.evaluateExpressionValue(instanceClass).GetObjectDescription() instanceClass = fb.evaluateExpression("(id)[(id)" + instanceClass + " superclass]")
def _responderChain(startResponder): responderAddress = fb.evaluateExpression(startResponder) while int(responderAddress, 16): yield fb.evaluateExpressionValue( responderAddress).GetObjectDescription() responderAddress = fb.evaluateExpression("(id)[(id)" + responderAddress + " nextResponder]")
def subviewsOfView(view): views = [(view, 0)] yield views[0] while views: (view, level) = views.pop(0) subviews = fb.evaluateExpression("(id)[%s subviews]" % view) subviewsCount = int( fb.evaluateExpression("(int)[(id)%s count]" % subviews)) for i in range(subviewsCount): subview = fb.evaluateExpression("(id)[%s objectAtIndex:%i]" % (subviews, i)) views.append((subview, level + 1)) yield (subview, level + 1)
def generateKey(arguments): keyFormatString = arguments[1] keyArgs = [] for argument in arguments[2:]: if argument.startswith('('): value = fb.evaluateExpression(argument) else: value = fb.evaluateExpressionValue(argument).GetObjectDescription() if not value: value = fb.evaluateExpression(argument) keyArgs.append(value) return keyFormatString.format(*keyArgs).strip()
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 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]" # noqa B950 % view)
def printInvocationForFrame(frame): print(frame) symbolName = frame.GetSymbol().GetName() if not re.match(r"[-+]\s*\[.*\]", symbolName): return self = findArgAtIndexFromStackFrame(frame, 0) cmd = findArgAtIndexFromStackFrame(frame, 1) commandForSignature = ( "[(id)" + self + " methodSignatureForSelector:(char *)sel_getName((SEL)" + cmd + ")]") signatureValue = fb.evaluateExpressionValue("(id)" + commandForSignature) if (signatureValue.GetError() is not None and str(signatureValue.GetError()) != "success"): print( "My sincerest apologies. I couldn't find a method signature for the selector." # noqa B950 ) return signature = signatureValue.GetValue() arg0 = stackStartAddressInSelectedFrame(frame) commandForInvocation = ( "[NSInvocation _invocationWithMethodSignature:(id)" + signature + " frame:((void *)" + str(arg0) + ")]") invocation = fb.evaluateExpression("(id)" + commandForInvocation) if invocation: prettyPrintInvocation(frame, invocation) else: print(frame)
def _showPixelBuffer(target): fb.evaluateExpression("CGImageRef $imageOut = NULL") fb.evaluateExpression("(OSStatus)VTCreateCGImageFromCVPixelBuffer(" + target + ", NULL, &$imageOut)") image = fb.evaluateExpression("[UIImage imageWithCGImage:$imageOut]") _showImage(image) fb.evaluateExpression("CGImageRelease($imageOut)")
def convertToLayer(viewOrLayer): if fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[CALayer class]]" % viewOrLayer): return viewOrLayer elif fb.evaluateBooleanExpression( "[(id)%s respondsToSelector:(SEL)@selector(layer)]" % viewOrLayer): return fb.evaluateExpression("(CALayer *)[%s layer]" % viewOrLayer) else: raise Exception("Argument must be a CALayer, UIView, or NSView.")
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 toPNG = "(id)UIImagePNGRepresentation((id){})".format(commandForImage) imageDataAddress = fb.evaluateExpressionValue( toPNG, tryAllThreads=True).GetValue() 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: with open(imagePath, "wb") as imgFile: imgFile.write(mem) os.system("open " + imagePath)
def maskView(viewOrLayer, color, alpha): unmaskView(viewOrLayer) window = fb.evaluateExpression( "(UIWindow *)[[UIApplication sharedApplication] keyWindow]") origin = convertPoint(0, 0, viewOrLayer, window) size = fb.evaluateExpressionValue("(CGSize)((CGRect)[(id)%s frame]).size" % viewOrLayer) rectExpr = "(CGRect){{%s, %s}, {%s, %s}}" % ( origin.GetChildMemberWithName("x").GetValue(), origin.GetChildMemberWithName("y").GetValue(), size.GetChildMemberWithName("width").GetValue(), size.GetChildMemberWithName("height").GetValue(), ) mask = fb.evaluateExpression("(id)[[UIView alloc] initWithFrame:%s]" % rectExpr) fb.evaluateEffect("[%s setTag:(NSInteger)%s]" % (mask, viewOrLayer)) fb.evaluateEffect("[%s setBackgroundColor:[UIColor %sColor]]" % (mask, color)) fb.evaluateEffect("[%s setAlpha:(CGFloat)%s]" % (mask, alpha)) fb.evaluateEffect("[%s addSubview:%s]" % (window, mask)) flushCoreAnimationTransaction()
def run(self, arguments, options): object = fb.evaluateInputExpression(arguments[0]) ivarName = arguments[1] objectClass = fb.evaluateExpressionValue( "(id)[(" + object + ") class]").GetObjectDescription() ivarTypeCommand = '((char *)ivar_getTypeEncoding((void*)object_getInstanceVariable((id){}, "{}", 0)))[0]'.format( # noqa B950 object, ivarName) ivarTypeEncodingFirstChar = fb.evaluateExpression(ivarTypeCommand) result = fb.evaluateExpressionValue("(({} *)({}))->{}".format( objectClass, object, ivarName)) print(result.GetObjectDescription() if "@" in ivarTypeEncodingFirstChar else result)
def run(self, arguments, options): upwards = "YES" if options.upwards else "NO" showViews = "YES" if options.showViews == "YES" else "NO" view = fb.evaluateInputExpression(arguments[0]) if not viewHelpers.isView(view): # assume it's a CKComponent view = fb.evaluateExpression( "((CKComponent *)%s).viewContext.view" % view) print( fb.describeObject( "[CKComponentHierarchyDebugHelper componentHierarchyDescriptionForView:(UIView *)" # noqa B950 + view + " searchUpwards:" + upwards + " showViews:" + showViews + "]"))
def _copyFromData(data, defaultFilename, preferredFilename, noOpen): directory = '/tmp/chisel_copy/' path = directory + (preferredFilename or defaultFilename) try: os.makedirs(directory) except OSError as e: if e.errno == errno.EEXIST and os.path.isdir(directory): pass else: raise startAddress = fb.evaluateExpression('(void *)[(id)' + data + ' bytes]') length = fb.evaluateExpression('(NSUInteger)[(id)' + data + ' length]') address = int(startAddress, 16) length = int(length) if not (address or length): print('Could not get 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: with open(path, 'wb') as file: file.write(mem) file.close() print(path) if not noOpen: os.system('open ' + path)
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 upwardsRecursiveDescription(view, maxDepth=0): if not fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[UIView class]]" % view) and not fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[NSView class]]" % view): return None currentView = view recursiveDescription = [] depth = 0 while currentView and (maxDepth <= 0 or depth <= maxDepth): depth += 1 viewDescription = fb.evaluateExpressionValue( "(id)[%s debugDescription]" % (currentView)).GetObjectDescription() currentView = fb.evaluateExpression("(void*)[%s superview]" % (currentView)) try: if int(currentView, 0) == 0: currentView = None except Exception: currentView = None if viewDescription: recursiveDescription.insert(0, viewDescription) if not len(viewDescription): return None currentPrefix = "" builder = "" for viewDescription in recursiveDescription: builder += currentPrefix + viewDescription + "\n" currentPrefix += " | " return builder
def generateTmpFilePath(self): return "/tmp/curl_data_{}".format( fb.evaluateExpression( "(NSTimeInterval)[NSDate timeIntervalSinceReferenceDate]"))
def object_getClass(object): command = "(void*)object_getClass((id){})".format(object) value = fb.evaluateExpression(command) return value
def objc_getClass(className): command = '(void*)objc_getClass("{}")'.format(className) value = fb.evaluateExpression(command) return value
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( # noqa B950 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' # noqa B950 ) 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 findArgAtIndexFromStackFrame(frame, index): return fb.evaluateExpression( "*(int *)" + str(findArgAdressAtIndexFromStackFrame(frame, index)))
def class_getSuperclass(klass): command = "(void*)class_getSuperclass((Class){})".format(klass) value = fb.evaluateExpression(command) return value
def viewsCount(views): return int(fb.evaluateExpression("(int)[%s count]" % views))
def class_getInstanceMethod(klass, selector): command = "(void*)class_getInstanceMethod((Class){}, @selector({}))".format( klass, selector) value = fb.evaluateExpression(command) return value