def properties(debugger, command, exe_ctx, result, internal_dict): """ Syntax: properties <className/classInstance> Examples: (lldb) properties UIViewController (lldb) properties [NSObject new] (lldb) expression -l objc -O -- [NSObject new] <NSObject: 0x60000372f760> (lldb) properties 0x60000372f760 This command is implemented in HMClassInfoCommands.py """ if len(command) == 0: HM.DPrint( "Requires a argument, Please enter \"help properties\" for help.") return value = HM.evaluateExpressionValue( expression= f'(NSString *)[{command} performSelector:NSSelectorFromString(@"_propertyDescription")]', printErrors=False) if HM.successOfSBError(value.GetError()): HM.DPrint(value.GetObjectDescription()) return clsPrefixesValue = HM.getClassPrefixes()[1] command_script = f''' Class inputClass = objc_lookUpClass("{command}"); if (inputClass == nil) {{ // Find prefixed class for (NSString *prefix in (NSMutableArray *){clsPrefixesValue.GetValue()}) {{ NSString *clsName = [prefix stringByAppendingString:@".{command}"]; inputClass = objc_lookUpClass((char *)[clsName UTF8String]); if (inputClass) {{ break; }} }} }} NSMutableString *result = [[NSMutableString alloc] init]; if (inputClass == nil) {{ [result appendString:@"Unable to resolve {command} or find {command} class, maybe {command} is not a subclass of NSObject\\n"]; }} else {{ if ((BOOL)[(Class)inputClass respondsToSelector:(SEL)NSSelectorFromString(@"_propertyDescription")]) {{ [result appendString:(NSString *)[inputClass performSelector:NSSelectorFromString(@"_propertyDescription")]]; }} else {{ [result appendString:@"{command} is not a subclass of NSObject"]; }} }} result; ''' result = HM.evaluateExpressionValue(command_script).GetObjectDescription() HM.DPrint(result)
def findSuperClass(debugger, command, exe_ctx, result, internal_dict): """ Syntax: fsuperclass <className> Examples: (lldb) fsuperclass UIButton This command is implemented in HMClassInfoCommands.py """ if len(command) == 0: HM.DPrint( "Requires a argument, Please enter \"help fsuperclass\" for help.") return clsPrefixesValue = HM.getClassPrefixes()[1] command_script = f''' Class inputClass = objc_lookUpClass("{command}"); if (inputClass == nil) {{ // Find prefixed class for (NSString *prefix in (NSMutableArray *){clsPrefixesValue.GetValue()}) {{ NSString *clsName = [prefix stringByAppendingString:@".{command}"]; inputClass = objc_lookUpClass((char *)[clsName UTF8String]); if (inputClass) {{ break; }} }} }} NSMutableString *result = [[NSMutableString alloc] init]; if (inputClass == nil) {{ [result appendString:@"Can't find {command} class\\n"]; }} else {{ [result appendString:[[NSString alloc] initWithUTF8String:class_getName(inputClass)]]; for (Class superClass = class_getSuperclass(inputClass); superClass != nil; superClass = class_getSuperclass(superClass)) {{ NSString *name = [[NSString alloc] initWithUTF8String:class_getName(superClass)]; [result appendFormat:@" : %@", name]; }} }} result; ''' classNames = HM.evaluateExpressionValue( command_script).GetObjectDescription() HM.DPrint(classNames)
def push(debugger, command, exe_ctx, result, internal_dict): """ Syntax: push <className> push [--instance] <instance> Options: --instance/-i; Push the UIViewController instance. Examples: (lldb) push PersonalViewController (lldb) push -i [[PersonalViewController alloc] init] (lldb) expression -l objc -O -- [PersonalViewController new] <PersonalViewController: 0x7fed30c5a070> (lldb) push -i 0x7fed30c5a070 Notice: "push MyViewController" needs to execute "[[MyViewController alloc] init]" first. If the initializer of the class requires parameters, or the class needs to pass parameters after initialization, this command may cause errors. This command is implemented in HMPushViewController.py """ # HM.DPrint(type(command)) # <class 'str'> # HM.DPrint(type(exe_ctx)) # <class 'lldb.SBExecutionContext'> # HM.DPrint(type(result)) # <class 'lldb.SBCommandReturnObject'> # HM.DPrint(type(internal_dict)) # <class 'dict'> command_args = shlex.split(command) parser = generate_option_parser() try: # options: optparse.Values # args: list (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if len(args) == 0: HM.DPrint("Error input, plase enter 'help push' for more infomation") return HM.DPrint("Waiting...") navigationVC = getNavigationVC() if navigationVC is None: HM.DPrint("Cannot find a UINavigationController") return state = False if options.instance: instanceExpr: str = "" for string in args: instanceExpr += string + " " instanceExpr = instanceExpr.rstrip() VCObject = HM.evaluateExpressionValue(instanceExpr).GetValue() else: makeVCExpression = f"(UIViewController *)[[NSClassFromString(@\"{args[0]}\") alloc] init]" VCObject = HM.evaluateExpressionValue(makeVCExpression).GetValue() # address if verifyObjIsKindOfClass(VCObject, "UIViewController"): pushExpression = f"(void)[{navigationVC} pushViewController:(id){VCObject} animated:YES]" debugger.HandleCommand('expression -l objc -O -- ' + pushExpression) state = True elif not options.instance: classPrefixes = HM.getClassPrefixes()[0] for prefix in classPrefixes: # for Swift file className = f"{prefix}.{args[0]}" if not HM.existClass(className): continue makeVCExpression = f"(UIViewController *)[[NSClassFromString(@\"{className}\") alloc] init]" VCObject = HM.evaluateExpressionValue(makeVCExpression).GetValue() # address if verifyObjIsKindOfClass(VCObject, "UIViewController"): pushExpression = f"(void)[{navigationVC} pushViewController:(id){VCObject} animated:YES]" debugger.HandleCommand('expression -l objc -O -- ' + pushExpression) state = True break HM.DPrint("push succeed" if state else "push failed") if state: HM.processContinue()
def methods(debugger, command, exe_ctx, result, internal_dict): """ Syntax: methods [--short] <className/classInstance> Examples: (lldb) methods UIViewController (lldb) methods -s UIViewController (lldb) methods [UIView new] (lldb) expression -l objc -O -- [NSObject new] <NSObject: 0x60000375f9a0> (lldb) methods 0x60000375f9a0 Options: --short/-s; Use [inputClass _shortMethodDescription] instead of [inputClass _methodDescription] This command is implemented in HMClassInfoCommands.py """ command_args = shlex.split(command) parser = generate_methods_option_parser() try: # options: optparse.Values # args: list (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return inputStr: str = "" for string in args: inputStr += string + " " inputStr = inputStr.rstrip() if len(inputStr) == 0: HM.DPrint( "Requires a argument, Please enter \"help methods\" for help.") return if options.short: selName = "_shortMethodDescription" else: selName = "_methodDescription" value = HM.evaluateExpressionValue( expression= f'(NSString *)[{inputStr} performSelector:NSSelectorFromString(@"{selName}")]', printErrors=False) if HM.successOfSBError(value.GetError()): HM.DPrint(value.GetObjectDescription()) return clsPrefixesValue = HM.getClassPrefixes()[1] command_script = f''' Class inputClass = objc_lookUpClass("{inputStr}"); if (inputClass == nil) {{ // Find prefixed class for (NSString *prefix in (NSMutableArray *){clsPrefixesValue.GetValue()}) {{ NSString *clsName = [prefix stringByAppendingString:@".{inputStr}"]; inputClass = objc_lookUpClass((char *)[clsName UTF8String]); if (inputClass) {{ break; }} }} }} NSMutableString *result = [[NSMutableString alloc] init]; if (inputClass == nil) {{ [result appendString:@"Unable to resolve {inputStr} or find {inputStr} class, maybe {inputStr} is not a subclass of NSObject\\n"]; }} else {{ if ((BOOL)[(Class)inputClass respondsToSelector:(SEL)NSSelectorFromString(@"{selName}")]) {{ [result appendString:(NSString *)[inputClass performSelector:NSSelectorFromString(@"{selName}")]]; }} else {{ [result appendString:@"{inputStr} is not a subclass of NSObject"]; }} }} result; ''' result = HM.evaluateExpressionValue(command_script).GetObjectDescription() HM.DPrint(result)
def findMethod(debugger, command, exe_ctx, result, internal_dict): """ Syntax: fmethod <methodName> (Case insensitive.) fmethod [--class] <className> Options: --class/-c; Find all method in the class Examples: (lldb) fmethod viewdid (lldb) fmethod viewDidLayoutSubviews (lldb) fmethod -c UITableViewController This command is implemented in HMClassInfoCommands.py """ command_args = shlex.split(command) parser = generate_findMethod_option_parser() try: # options: optparse.Values # args: list (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if not options.cls: if len(args) != 1: HM.DPrint("Error input, Please enter \"help fmethod\" for help.") return elif len(args[0]) <= 5: HM.DPrint("Argument length must be greater than 5.") return HM.DPrint("Waiting...") if options.cls: clsPrefixesValue = HM.getClassPrefixes()[1] command_script = f''' NSMutableString *result = [[NSMutableString alloc] init]; Class inputClass = objc_lookUpClass("{options.cls}"); if (inputClass == nil) {{ // Find prefixed class for (NSString *prefix in (NSMutableArray *){clsPrefixesValue.GetValue()}) {{ NSString *clsName = [prefix stringByAppendingString:@".{options.cls}"]; inputClass = objc_lookUpClass((char *)[clsName UTF8String]); if (inputClass) {{ break; }} }} }} if (inputClass == nil) {{ [result appendString:@"Can't find {options.cls} class\\n"]; }} else {{ unsigned int instanceMethodCount; Method *instanceMethodList = class_copyMethodList(inputClass, &instanceMethodCount); for (int j = 0; j < instanceMethodCount; ++j) {{ Method method = instanceMethodList[j]; SEL sel = method_getName(method); NSString *selName = [[NSString alloc] initWithUTF8String:sel_getName(sel)]; [result appendFormat:@"(-) %@\\n\\tType encoding:%s\\n", selName, method_getTypeEncoding(method)]; }} free(instanceMethodList); unsigned int classMethodCount = 0; Class metaCls = object_getClass(inputClass); if (class_isMetaClass(metaCls)) {{ Method *classMethodList = class_copyMethodList(metaCls, &classMethodCount); for (int j = 0; j < classMethodCount; ++j) {{ Method method = classMethodList[j]; SEL sel = method_getName(method); NSString *selName = [[NSString alloc] initWithUTF8String:sel_getName(sel)]; [result appendFormat:@"(+) %@\\n\\tType encoding:%s\\n", selName, method_getTypeEncoding(method)]; }} free(classMethodList); }} if (instanceMethodCount + classMethodCount == 0) {{ [result insertString:@"No method found.\\n" atIndex:0]; }} else {{ [result insertString:[[NSString alloc] initWithFormat:@"Instance methods count: %u. Class method count: %u.\\n", instanceMethodCount, classMethodCount] atIndex:0]; NSString *clsName = [[NSString alloc] initWithUTF8String:class_getName(inputClass)]; [result insertString:[[NSString alloc] initWithFormat:@"Class: %@ (%p)\\n", clsName, inputClass] atIndex:0]; }} }} result; ''' else: inputMethodName = args[0].lower() command_script = f''' NSString *inputMethodName = [[NSString alloc] initWithUTF8String:"{inputMethodName}"]; NSMutableString *result = [[NSMutableString alloc] init]; unsigned int classCount; unsigned int findCount = 0; Class *classList = objc_copyClassList(&classCount); for (int i = 0; i < classCount; ++i) {{ Class cls = classList[i]; // Instance Methods unsigned int instanceMethodCount; Method *instanceMethodList = class_copyMethodList(cls, &instanceMethodCount); for (int j = 0; j < instanceMethodCount; ++j) {{ Method method = instanceMethodList[j]; SEL sel = method_getName(method); NSString *selName = [[NSString alloc] initWithUTF8String:sel_getName(sel)]; if ([[selName lowercaseString] containsString:inputMethodName]) {{ NSString *clsName = [[NSString alloc] initWithUTF8String:class_getName(cls)]; [result appendFormat:@"(-) %@\\n\\tType encoding:%s\\n\\tClass:%@\\n", selName, method_getTypeEncoding(method), clsName]; findCount += 1; }} }} free(instanceMethodList); // Class Methods Class metaCls = object_getClass(cls); if (!class_isMetaClass(metaCls)) {{ continue; }} unsigned int classMethodCount; Method *classMethodList = class_copyMethodList(metaCls, &classMethodCount); for (int j = 0; j < classMethodCount; ++j) {{ Method method = classMethodList[j]; SEL sel = method_getName(method); NSString *selName = [[NSString alloc] initWithUTF8String:sel_getName(sel)]; if ([[selName lowercaseString] containsString:inputMethodName]) {{ NSString *clsName = [[NSString alloc] initWithUTF8String:class_getName(cls)]; [result appendFormat:@"(+) %@\\n\\tType encoding:%s\\n\\tClass:%@\\n", selName, method_getTypeEncoding(method), clsName]; findCount += 1; }} }} free(classMethodList); }} if (findCount == 0) {{ [result insertString:@"No method found.\\n" atIndex:0]; }} else {{ [result insertString:[[NSString alloc] initWithFormat:@"Methods count: %u \\n", findCount] atIndex:0]; }} free(classList); result; ''' result = HM.evaluateExpressionValue(command_script).GetObjectDescription() HM.DPrint(result)
def findSubclass(debugger, command, exe_ctx, result, internal_dict): """ Syntax: fsubclass [--nonrecursively] <className> Options: --nonrecursively/-n; Find subclass non-recursively Examples: (lldb) fsubclass UIViewController (lldb) fsubclass -n UIViewController This command is implemented in HMClassInfoCommands.py """ command_args = shlex.split(command) parser = generate_findSubclass_option_parser() try: # options: optparse.Values # args: list (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if len(args) != 1: HM.DPrint( "Requires a argument, Please enter \"help fsubclass\" for help.") return HM.DPrint("Waiting...") if options.nonrecursively: compareScript = ''' if (class_getSuperclass(cls) == inputClass){ NSString *name = [[NSString alloc] initWithUTF8String:class_getName(cls)]; [result appendFormat:@"%@\\n", name]; findCount += 1; } ''' else: compareScript = ''' for (Class superClass = class_getSuperclass(cls); superClass != nil; superClass = class_getSuperclass(superClass)) { if (superClass == inputClass) { NSString *name = [[NSString alloc] initWithUTF8String:class_getName(cls)]; [result appendFormat:@"%@\\n", name]; findCount += 1; break; } } ''' clsPrefixesValue = HM.getClassPrefixes()[1] command_script = f''' Class inputClass = objc_lookUpClass("{args[0]}"); if (inputClass == nil) {{ // Find prefixed class for (NSString *prefix in (NSMutableArray *){clsPrefixesValue.GetValue()}) {{ NSString *clsName = [prefix stringByAppendingString:@".{args[0]}"]; inputClass = objc_lookUpClass((char *)[clsName UTF8String]); if (inputClass) {{ break; }} }} }} NSMutableString *result = [[NSMutableString alloc] init]; if (inputClass == nil) {{ [result appendString:@"Can't find {args[0]} class\\n"]; }} else {{ unsigned int classCount; unsigned int findCount = 0; Class *classList = objc_copyClassList(&classCount); for (int i = 0; i < classCount; i++) {{ Class cls = classList[i]; {compareScript} }} if (findCount == 0) {{ [result insertString:@"No subclass found.\\n" atIndex:0]; }} else {{ [result insertString:[[NSString alloc] initWithFormat:@"Subclass count: %u \\n", findCount] atIndex:0]; }} free(classList); }} result; ''' classNames = HM.evaluateExpressionValue( command_script).GetObjectDescription() HM.DPrint(classNames)