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 loadChiselIfNecessary(self): target = lldb.debugger.GetSelectedTarget() symbol_contexts = target.FindSymbols("PrintInstances", lldb.eSymbolTypeCode) if any(ctx.symbol.IsValid() for ctx in symbol_contexts): return True path = self.chiselLibraryPath() if not os.path.exists(path): print("Chisel library missing: " + path) return False module = fb.evaluateExpressionValue('(void*)dlopen("{}", 2)'.format(path)) if module.unsigned != 0 or target.module["Chisel"]: return True # `errno` is a macro that expands to a call to __error(). In development, # lldb was not getting a correct value for `errno`, so `__error()` is used. errno = fb.evaluateExpressionValue("*(int*)__error()").value error = fb.evaluateExpressionValue("(char*)dlerror()") if errno == 50: # KERN_CODESIGN_ERROR from <mach/kern_return.h> print("Error loading Chisel: Code signing failure; Must re-run codesign") elif error.unsigned != 0: print("Error loading Chisel: " + error.summary) elif errno != 0: error = fb.evaluateExpressionValue("(char*)strerror({})".format(errno)) if error.unsigned != 0: print("Error loading Chisel: " + error.summary) else: print("Error loading Chisel (errno {})".format(errno)) else: print("Unknown error loading Chisel") return False
def import_uikit(): """ Import UIKit framework to the debugger """ global _uikit_imported if _uikit_imported: return _uikit_imported = True fb.evaluateExpressionValue("@import UIKit")
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 depth(self): """ :return: XCUIElement depth :rtype: lldb.SBValue """ return fb.evaluateExpressionValue("(int)[{} depth]".format( self.element_value))
def suggested_hit_points(self): """ :return: XCUIElement suggested hit points :rtype: lldb.SBValue """ return fb.evaluateExpressionValue( "(NSArray *)[{} suggestedHitpoints]".format(self.element_value))
def run(self, arguments, options): if not self.loadChiselIfNecessary(): return if len(arguments) == 0 or not arguments[0].strip(): print( "Usage: findinstances <classOrProtocol> [<predicate>]; Run `help findinstances`" ) return query = arguments[0] predicate = arguments[1].strip() # Escape double quotes and backslashes. predicate = re.sub('([\\"])', r"\\\1", predicate) call = '(void)PrintInstances("{}", "{}")'.format(query, predicate) fb.evaluateExpressionValue(call)
def accessibilityLabel(view): # using Apple private API to get real value of accessibility string for element. return fb.evaluateExpressionValue( "(id)[%s accessibilityAttributeValue:%i]" % (view, ACCESSIBILITY_LABEL_KEY), False, )
def run(self, arguments, options): element = arguments[0] language = fb.currentLanguage() if element == "__default__": element = ("XCUIApplication()" if language == lldb.eLanguageTypeSwift else "(XCUIApplication *)[[XCUIApplication alloc] init]") # Evaluate object element_sbvalue = fb.evaluateExpressionValue("{}".format(element), language=language) """:type: lldb.SBValue""" # Get pointer value, so it will be working in Swift and Objective-C element_pointer = int(element_sbvalue.GetValue(), 16) # Get XCElementSnapshot object snapshot = take_snapshot(element_pointer) # Print tree for snapshot element snapshot_object = XCElementSnapshot(snapshot, language=language) elements = snapshot_object.find_missing_identifiers( status_bar=options.status_bar) if elements is not None: print( elements.hierarchy_text(pointer=options.pointer, trait=options.trait, frame=options.frame)) else: print("Couldn't found elements without identifier")
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 _showLayer(layer): layer = "(" + layer + ")" size = "((CGRect)[(id)" + layer + " bounds]).size" width = float(fb.evaluateExpression("(CGFloat)(" + size + ".width)")) height = float(fb.evaluateExpression("(CGFloat)(" + size + ".height)")) if width == 0.0 or height == 0.0: print("Nothing to see here - the size of this element is {} x {}.". format(width, height)) return fb.evaluateEffect("UIGraphicsBeginImageContextWithOptions(" + size + ", NO, 0.0)") fb.evaluateEffect( "[(id)" + layer + " renderInContext:(void *)UIGraphicsGetCurrentContext()]") result = fb.evaluateExpressionValue( "(UIImage *)UIGraphicsGetImageFromCurrentImageContext()") if result.GetError() is not None and str(result.GetError()) != "success": print(result.GetError()) else: image = result.GetValue() _showImage(image) fb.evaluateEffect("UIGraphicsEndImageContext()")
def _responderChain(startResponder): responderAddress = fb.evaluateExpression(startResponder) while int(responderAddress, 16): yield fb.evaluateExpressionValue(responderAddress).GetObjectDescription() responderAddress = fb.evaluateExpression( "(id)[(id)" + responderAddress + " nextResponder]" )
def is_top_level_touch_bar_element(self): """ :return: XCUIElement is top level touch bar element :rtype: lldb.SBValue """ return fb.evaluateExpressionValue( "(BOOL)[{} isTopLevelTouchBarElement]".format(self.element_value))
def _viewControllerDescription(viewController): vc = "(%s)" % (viewController) if fb.evaluateBooleanExpression("[(id)%s isViewLoaded]" % (vc)): result = fb.evaluateExpressionValue( '(id)[[NSString alloc] initWithFormat:@"<%%@: %%p; view = <%%@; %%p>; frame = (%%g, %%g; %%g, %%g)>", (id)NSStringFromClass((id)[(id)%s class]), %s, (id)[(id)[(id)%s view] class], (id)[(id)%s view], ((CGRect)[(id)[(id)%s view] frame]).origin.x, ((CGRect)[(id)[(id)%s view] frame]).origin.y, ((CGRect)[(id)[(id)%s view] frame]).size.width, ((CGRect)[(id)[(id)%s view] frame]).size.height]' # noqa B950 % (vc, vc, vc, vc, vc, vc, vc, vc)) else: result = fb.evaluateExpressionValue( '(id)[[NSString alloc] initWithFormat:@"<%%@: %%p; view not loaded>", (id)NSStringFromClass((id)[(id)%s class]), %s]' # noqa B950 % (vc, vc)) if result.GetError() is not None and str(result.GetError()) != "success": return "[Error getting description.]" else: return result.GetObjectDescription()
def run(self, arguments, options): tableView = tableViewInHierarchy() print( fb.evaluateExpressionValue( "(id)[(id)" + tableView + " visibleCells]" ).GetObjectDescription() )
def tableViewInHierarchy(): viewDescription = fb.evaluateExpressionValue( "(id)[(id)[[UIApplication sharedApplication] keyWindow] recursiveDescription]" ).GetObjectDescription() searchView = None # Try to find an instance of classPattern = re.compile(r"UITableView: (0x[0-9a-fA-F]+);") for match in re.finditer(classPattern, viewDescription): searchView = match.group(1) break # Try to find a direct subclass if not searchView: subclassPattern = re.compile( r"(0x[0-9a-fA-F]+); baseClass = UITableView;") for match in re.finditer(subclassPattern, viewDescription): searchView = match.group(1) break # SLOW: check every pointer in town if not searchView: pattern = re.compile(r"(0x[0-9a-fA-F]+)[;>]") for view in re.findall(pattern, viewDescription): if fb.evaluateBooleanExpression( "[" + view + " isKindOfClass:(id)[UITableView class]]"): searchView = view break return searchView
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 _showColor(color): color = "(" + color + ")" colorToUse = color isCF = _colorIsCGColorRef(color) if isCF: colorToUse = "[[UIColor alloc] initWithCGColor:(CGColorRef){}]".format( color) else: isCI = objectHelpers.isKindOfClass(color, "CIColor") if isCI: colorToUse = "[UIColor colorWithCIColor:(CIColor *){}]".format( color) imageSize = 58 fb.evaluateEffect( "UIGraphicsBeginImageContextWithOptions((CGSize)CGSizeMake({imageSize}, {imageSize}), NO, 0.0)" .format(imageSize=imageSize)) fb.evaluateEffect("[(id){} setFill]".format(colorToUse)) fb.evaluateEffect( "UIRectFill((CGRect)CGRectMake(0.0, 0.0, {imageSize}, {imageSize}))". format(imageSize=imageSize)) result = fb.evaluateExpressionValue( "(UIImage *)UIGraphicsGetImageFromCurrentImageContext()") if result.GetError() is not None and str(result.GetError()) != "success": print("got error {}".format(result)) print(result.GetError()) else: image = result.GetValue() _showImage(image) fb.evaluateEffect("UIGraphicsEndImageContext()")
def uniquely_identifying_objective_c_code(self): """ :return: XCUIElement uniquely identifying Objective-C code :rtype: lldb.SBValue """ return fb.evaluateExpressionValue( "(id)[{} _uniquelyIdentifyingObjectiveCCode]".format( self.element_value))
def isIOSSimulator(): return ( fb.evaluateExpressionValue("(id)[[UIDevice currentDevice] model]") .GetObjectDescription() .lower() .find("simulator") >= 0 )
def hit_point_for_scrolling(self): """ :return: XCUIElement hit point for scrolling :rtype: lldb.SBValue """ import_uikit() return fb.evaluateExpressionValue( "(CGPoint)[{} hitPointForScrolling]".format(self.element_value))
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 uniquely_identifying_swift_code(self): """ :return: XCUIElement uniquely identifying Swift code :rtype: lldb.SBValue """ return fb.evaluateExpressionValue( "(id)[{} _uniquelyIdentifyingSwiftCode]".format( self.element_value))
def visible_frame(self): """ :return: XCUIElement visible frame :rtype: lldb.SBValue """ import_uikit() return fb.evaluateExpressionValue("(CGRect)[{} visibleFrame]".format( self.element_value))
def run(self, arguments, options): maxDepth = int(options.depth) window = int(options.window) isMac = runtimeHelpers.isMacintoshArch() if window > 0: if isMac: arguments[0] = ( "(id)[[[[NSApplication sharedApplication] windows] objectAtIndex:" + str(window) + "] contentView]" ) else: arguments[0] = ( "(id)[[[UIApplication sharedApplication] windows] objectAtIndex:" + str(window) + "]" ) elif arguments[0] == "__keyWindow_dynamic__": if isMac: arguments[ 0 ] = "(id)[[[[NSApplication sharedApplication] windows] objectAtIndex:0] contentView]" else: arguments[0] = "(id)[[UIApplication sharedApplication] keyWindow]" if options.upwards: view = arguments[0] description = viewHelpers.upwardsRecursiveDescription(view, maxDepth) if description: print(description) else: 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: printingMethod = "_subtreeDescription" description = fb.evaluateExpressionValue( "(id)[" + arguments[0] + " " + printingMethod + "]" ).GetObjectDescription() if maxDepth > 0: separator = re.escape(" | ") prefixToRemove = separator * maxDepth + " " description += "\n" description = re.sub(r"%s.*\n" % (prefixToRemove), r"", description) if options.short: toRemove = ":.*(?:\n|$)" description = re.sub(toRemove, r">\n", description) elif options.medium: toRemove = ";.*(?:\n|$)" description = re.sub(toRemove, r">\n", description) print(description)
def run(self, arguments, options): lldbOutput = fb.evaluateExpressionValue( "[{changeset} description]".format( changeset=arguments[0])).GetObjectDescription() process = subprocess.Popen("pbcopy", env={"LANG": "en_US.UTF-8"}, stdin=subprocess.PIPE) process.communicate(lldbOutput.encode("utf-8")) print("Object copied to clipboard")
def run(self, arguments, options): path = fb.evaluateExpressionValue( "(NSString*)[[NSBundle mainBundle] bundlePath]") pathString = "{}".format(path).split('"')[1] cmd = 'echo {} | tr -d "\n" | pbcopy'.format(pathString) os.system(cmd) print(pathString) if options.open: os.system("open " + pathString)
def run(self, arguments, options): tableView = tableViewInHierarchy() if tableView: viewValue = fb.evaluateExpressionValue(tableView) print(viewValue.GetObjectDescription()) cmd = 'echo %s | tr -d "\n" | pbcopy' % tableView os.system(cmd) else: print("Sorry, chump. I couldn't find a table-view. :'(")
def run(self, arguments, options): element = arguments[0] language = fb.currentLanguage() if element == "__default__": element = ("XCUIApplication()" if language == lldb.eLanguageTypeSwift else "(XCUIApplication *)[[XCUIApplication alloc] init]") if language == lldb.eLanguageTypeSwift: print( fb.evaluateExpressionValue( "{}.debugDescription".format(element), language=language).GetObjectDescription().replace( "\\n", "\n").replace("\\'", "'").strip(' "\n\t')) else: print( fb.evaluateExpressionValue("[{} debugDescription]".format( element)).GetObjectDescription())
def _dataIsImage(data): data = "(" + data + ")" result = fb.evaluateExpressionValue("(id)[UIImage imageWithData:" + data + "]") if result.GetError() is not None and str(result.GetError()) != "success": return False else: isImage = result.GetValueAsUnsigned() != 0 return isImage