-
Notifications
You must be signed in to change notification settings - Fork 805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add two commands pclassmethod and pinstancemethod #113
Merged
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
52c8500
Merge pull request #1 from facebook/master
longv2go 44477a9
Merge pull request #2 from facebook/master
longv2go bfc1bcd
Merge pull request #3 from facebook/master
longv2go 01cd621
Merge pull request #4 from facebook/master
longv2go 5e46ca7
Merge pull request #5 from facebook/master
longv2go 48beada
add class dump
d59b1d3
fix
c910d48
add pclassmethods command
cab9666
change error log
37f5a96
handle error
34a5152
change FBPrintClassInstanceMethods command name
c701083
fix bug
57a4055
combine the pclassmethods and pinstancemehtods
df9db7c
pmethods can take an instance para
05a0671
add new option '-a'
1799ee0
Fix an issue to cause lldb run failed
1967de6
add comment
b59e8fa
change the impletation of pmethods with json
f967b1d
Merge remote-tracking branch 'facebook/master' into fb_classdump
31b6e2d
rename the eval to evaluate and move it to fblldbbase
c5b33d1
fix typo mistake
3b39c3c
Merge remote-tracking branch 'facebook/master'
c4870d5
Merge branch 'fb_classdump'
3299b90
fix typo error
2fba2df
Remove no need import
695049b
Fix typo in FBClassDump.py
a0c0540
Fix bug in check_expr
3154bb3
Remove unnessary cast in class_isMetaClass
c6eb2b2
Fix typo on fblldbbase.py
4f2f0ec
Fix description of pmethods
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
#!/usr/bin/python | ||
import string | ||
import lldb | ||
import fblldbbase as fb | ||
import fblldbobjcruntimehelpers as runtimeHelpers | ||
|
||
def lldbcommands(): | ||
return [ | ||
FBPrintMethods() | ||
] | ||
|
||
class FBPrintMethods(fb.FBCommand): | ||
def name(self): | ||
return 'pmethods' | ||
|
||
def description(self): | ||
return 'Print the class and instance methods of a class.' | ||
|
||
def options(self): | ||
return [ | ||
fb.FBCommandArgument(short='-a', long='--address', arg='showaddr', help='Print the implementation address of the method', default=False, boolean=True), | ||
fb.FBCommandArgument(short='-i', long='--instance', arg='insmethod', help='Print the instance methods', default=False, boolean=True), | ||
fb.FBCommandArgument(short='-c', long='--class', arg='clsmethod', help='Print the class methods', default=False, boolean=True) | ||
] | ||
|
||
def args(self): | ||
return [ fb.FBCommandArgument(arg='class or instance', type='instance or Class', help='an Objective-C Class.') ] | ||
|
||
def run(self, arguments, options): | ||
cls = arguments[0] | ||
if not isClassObject(cls): | ||
cls = runtimeHelpers.object_getClass(cls) | ||
if not isClassObject(cls): | ||
raise Exception('Invalid argument. Please specify an instance or a Class.') | ||
|
||
if options.clsmethod: | ||
print 'Class Methods:' | ||
printClassMethods(cls, options.showaddr) | ||
|
||
if options.insmethod: | ||
print '\nInstance Methods:' | ||
printInstanceMethods(cls, options.showaddr) | ||
|
||
if not options.clsmethod and not options.insmethod: | ||
print 'Class Methods:' | ||
printClassMethods(cls, options.showaddr) | ||
print '\nInstance Methods:' | ||
printInstanceMethods(cls, options.showaddr) | ||
|
||
def isClassObject(arg): | ||
return runtimeHelpers.class_isMetaClass(runtimeHelpers.object_getClass(arg)) | ||
|
||
def printInstanceMethods(cls, showaddr=False, prefix='-'): | ||
json_method_array = get_oc_methods_json(cls) | ||
if not json_method_array: | ||
print "No methods were found" | ||
|
||
if json_method_array: | ||
for m in json_method_array: | ||
method = Method(m) | ||
|
||
if showaddr: | ||
print prefix + ' ' + method.prettyPrintString() + ' ' + str(method.imp) | ||
else: | ||
print prefix + ' ' + method.prettyPrintString() | ||
|
||
def printClassMethods(cls, showaddr=False): | ||
printInstanceMethods(runtimeHelpers.object_getClass(cls), showaddr, '+') | ||
|
||
# Notice that evaluateExpression doesn't work with variable arguments. such as -[NSString stringWithFormat:] | ||
# I remove the "free(methods)" because it would cause evaluateExpressionValue to raise exception some time. | ||
def get_oc_methods_json(klass): | ||
tmpString = """ | ||
unsigned int outCount; | ||
Method *methods = (Method *)class_copyMethodList((Class)$cls, &outCount); | ||
NSMutableArray *result = (id)[NSMutableArray array]; | ||
|
||
for (int i = 0; i < outCount; i++) { | ||
NSMutableDictionary *m = (id)[NSMutableDictionary dictionary]; | ||
|
||
SEL name = (SEL)method_getName(methods[i]); | ||
[m setObject:(id)NSStringFromSelector(name) forKey:@"name"]; | ||
|
||
char * encoding = (char *)method_getTypeEncoding(methods[i]); | ||
[m setObject:(id)[NSString stringWithUTF8String:encoding] forKey:@"type_encoding"]; | ||
|
||
NSMutableArray *types = (id)[NSMutableArray array]; | ||
NSInteger args = (NSInteger)method_getNumberOfArguments(methods[i]); | ||
for (int idx = 0; idx < args; idx++) { | ||
char *type = (char *)method_copyArgumentType(methods[i], idx); | ||
[types addObject:(id)[NSString stringWithUTF8String:type]]; | ||
} | ||
[m setObject:types forKey:@"parameters_type"]; | ||
|
||
char *ret_type = (char *)method_copyReturnType(methods[i]); | ||
[m setObject:(id)[NSString stringWithUTF8String:ret_type] forKey:@"return_type"]; | ||
|
||
long imp = (long)method_getImplementation(methods[i]); | ||
[m setObject:[NSNumber numberWithLongLong:imp] forKey:@"implementation"]; | ||
|
||
[result addObject:m]; | ||
} | ||
RETURN(result); | ||
""" | ||
command = string.Template(tmpString).substitute(cls=klass) | ||
return fb.evaluate(command) | ||
|
||
|
||
class Method: | ||
|
||
encodeMap = { | ||
'c': 'char', | ||
'i': 'int', | ||
's': 'short', | ||
'l': 'long', | ||
'q': 'long long', | ||
|
||
'C': 'unsigned char', | ||
'I': 'unsigned int', | ||
'S': 'unsigned short', | ||
'L': 'unsigned long', | ||
'Q': 'unsigned long long', | ||
|
||
'f': 'float', | ||
'd': 'double', | ||
'B': 'bool', | ||
'v': 'void', | ||
'*': 'char *', | ||
'@': 'id', | ||
'#': 'Class', | ||
':': 'SEL', | ||
} | ||
|
||
def __init__(self, json): | ||
self.name = json['name'] | ||
self.type_encoding = json['type_encoding'] | ||
self.parameters_type = json['parameters_type'] | ||
self.return_type = json['return_type'] | ||
self.imp = self.toHex(json['implementation']) | ||
|
||
def prettyPrintString(self): | ||
argnum = len(self.parameters_type) | ||
names = self.name.split(':') | ||
|
||
# the argnum count must be bigger then 2, index 0 for self, index 1 for SEL | ||
for i in range(2, argnum): | ||
arg_type = self.parameters_type[i] | ||
names[i-2] = names[i-2] + ":(" + self.decode(arg_type) + ")arg" + str(i-2) | ||
|
||
string = " ".join(names) | ||
return "({}){}".format(self.decode(self.return_type), string) | ||
|
||
|
||
def decode(self, type): | ||
ret = type | ||
if type in Method.encodeMap: | ||
ret = Method.encodeMap[type] | ||
return ret | ||
|
||
def toHex(self, addr): | ||
return hex(addr) | ||
|
||
def __str__(self): | ||
return "<Method:" + self.oc_method + "> " + self.name + " --- " + self.type + " --- " + self.imp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,10 @@ def class_getSuperclass(klass): | |
value = fb.evaluateExpression(command) | ||
return value | ||
|
||
def class_isMetaClass(klass): | ||
command = 'class_isMetaClass((Class){})'.format(klass) | ||
return fb.evaluateBooleanExpression(command) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @longv2go You don't need the |
||
|
||
def class_getInstanceMethod(klass, selector): | ||
command = '(void*)class_getInstanceMethod((Class){}, @selector({}))'.format(klass, selector) | ||
value = fb.evaluateExpression(command) | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method looks superfluous.