Skip to content

Commit e3f84a6

Browse files
author
董宏昌
committed
Add print capture variables for pblock
before: Imp: 0x10a451d40 Signature: void ^(); after: Imp: 0x10a451d40 Signature: void ^() Variables : { <ViewController: 0x7fdd9b204060> <AppDelegate: 0x60c00002acc0> };
1 parent f7f5a88 commit e3f84a6

File tree

2 files changed

+104
-11
lines changed

2 files changed

+104
-11
lines changed

commands/FBClassDump.py

Lines changed: 98 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,108 @@ def run(self, arguments, options):
139139
command = string.Template(tmpString).substitute(block=block)
140140
json = fb.evaluate(command)
141141

142+
variables_json = self.getBlockVariables(block)
143+
if variables_json is not None:
144+
json.update(variables_json)
145+
146+
variablesStrs = []
147+
for i in range(10):
148+
varKey = 'variables['+str(i)+']'
149+
if varKey in json:
150+
variablesStrs.append(json[varKey])
151+
variablesStr = '\n'.join(variablesStrs)
152+
142153
signature = json['signature']
143154
if not signature:
144-
print 'Imp: ' + hex(json['invoke'])
155+
print 'Imp: ' + hex(json['invoke']) + ' Variables : {\n'+variablesStr+'\n};'
145156
return
146157

147158
sigStr = '{} ^('.format(decode(signature[0]))
148159
# the block`s implementation always take the block as it`s first argument, so we ignore it
149160
sigStr += ', '.join([decode(m) for m in signature[2:]])
150-
sigStr += ');'
161+
sigStr += ')'
151162

152-
print 'Imp: ' + hex(json['invoke']) + ' Signature: ' + sigStr
163+
print 'Imp: ' + hex(json['invoke']) + ' Signature: ' + sigStr + ' Variables : {\n'+variablesStr+'\n};'
164+
165+
def getBlockVariables(self, block, min_var_count=1, max_var_count=20):
166+
'''
167+
no __Block_byref_xxx
168+
'''
169+
170+
# http://clang.llvm.org/docs/Block-ABI-Apple.html
171+
tmpString = """
172+
#define BLOCK_VARIABLES_COUNT ($variables_count)
173+
enum {
174+
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
175+
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
176+
BLOCK_IS_GLOBAL = (1 << 28),
177+
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
178+
BLOCK_HAS_SIGNATURE = (1 << 30),
179+
};
180+
struct Block_literal_1 {
181+
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
182+
int flags;
183+
int reserved;
184+
void (*invoke)(void *, ...);
185+
struct Block_descriptor_1 {
186+
unsigned long int reserved; // NULL
187+
unsigned long int size; // sizeof(struct Block_literal_1)
188+
// optional helper functions
189+
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
190+
void (*dispose_helper)(void *src); // IFF (1<<25)
191+
// required ABI.2010.3.16
192+
const char *signature; // IFF (1<<30)
193+
} *descriptor;
194+
// imported variables
195+
Class *variables[BLOCK_VARIABLES_COUNT];
196+
};
197+
struct Block_literal_1 real = *((__bridge struct Block_literal_1 *)$block);
198+
NSMutableDictionary *dict = (id)[NSMutableDictionary dictionary];
199+
200+
// Get the list of classes and look for testPointerClass
201+
NSInteger numClasses = objc_getClassList(NULL, 0);
202+
Class *classesList = (Class*)malloc(sizeof(Class) * numClasses);
203+
numClasses = objc_getClassList(classesList, numClasses);
204+
205+
Class **blockVariables = real.variables;
206+
for (int i = 0; i < BLOCK_VARIABLES_COUNT; i++) {
207+
Class *obj = (Class*)blockVariables[i];
208+
if (obj == NULL) {
209+
break;
210+
}
211+
212+
Class testPointerClass = (Class)(*obj);
213+
BOOL isClass = NO;
214+
for (int i = 0; i < numClasses; i++)
215+
{
216+
if (classesList[i] == testPointerClass)
217+
{
218+
isClass = YES;
219+
break;
220+
}
221+
}
222+
if (!isClass) {
223+
break;
224+
}
225+
226+
NSString *key = [NSString stringWithFormat:@"variables[%d]", i];
227+
NSString *value = [NSString stringWithFormat:@"%@", obj];
228+
[dict setValue:value forKey:key];
229+
}
230+
231+
free(classesList);
232+
233+
RETURN(dict);
234+
"""
235+
last_json = None
236+
for i in range(min_var_count, max_var_count):
237+
command = string.Template(tmpString).substitute(block=block, variables_count=i)
238+
json = fb.evaluate(command, printErrors=False)
239+
if json is not None:
240+
last_json = json
241+
else:
242+
break
243+
return last_json
153244

154245
# helpers
155246
def isClassObject(arg):
@@ -302,20 +393,20 @@ def getProperties(klass):
302393
NSMutableDictionary *dict = (id)[NSMutableDictionary dictionary];
303394
304395
char *name = (char *)property_getName(props[i]);
305-
[dict setObject:(id)[NSString stringWithUTF8String:name] forKey:@"name"];
396+
[dict setValue:(id)[NSString stringWithUTF8String:name] forKey:@"name"];
306397
307398
char *attrstr = (char *)property_getAttributes(props[i]);
308-
[dict setObject:(id)[NSString stringWithUTF8String:attrstr] forKey:@"attributes_string"];
399+
[dict setValue:(id)[NSString stringWithUTF8String:attrstr] forKey:@"attributes_string"];
309400
310401
NSMutableDictionary *attrsDict = (id)[NSMutableDictionary dictionary];
311402
unsigned int pcount;
312403
objc_property_attribute_t *attrs = (objc_property_attribute_t *)property_copyAttributeList(props[i], &pcount);
313404
for (int i = 0; i < pcount; i++) {
314405
NSString *name = (id)[NSString stringWithUTF8String:(char *)attrs[i].name];
315406
NSString *value = (id)[NSString stringWithUTF8String:(char *)attrs[i].value];
316-
[attrsDict setObject:value forKey:name];
407+
[attrsDict setValue:value forKey:name];
317408
}
318-
[dict setObject:attrsDict forKey:@"attributes"];
409+
[dict setValue:attrsDict forKey:@"attributes"];
319410
320411
[result addObject:dict];
321412
}

fblldbbase.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,21 +168,23 @@ def check_expr(expr):
168168
# Example:
169169
# >>> fblldbbase.evaluate('NSString *str = @"hello world"; RETURN(@{@"key": str});')
170170
# {u'key': u'hello world'}
171-
def evaluate(expr):
171+
def evaluate(expr, printErrors=True):
172172
if not check_expr(expr):
173173
raise Exception("Invalid Expression, the last expression not include a RETURN family marco")
174174

175175
command = "({" + RETURN_MACRO + '\n' + expr + "})"
176-
ret = evaluateExpressionValue(command, printErrors=True)
176+
ret = evaluateExpressionValue(command, printErrors=printErrors)
177177
if not ret.GetError().Success():
178-
print ret.GetError()
178+
if printErrors:
179+
print ret.GetError()
179180
return None
180181
else:
181182
process = lldb.debugger.GetSelectedTarget().GetProcess()
182183
error = lldb.SBError()
183184
ret = process.ReadCStringFromMemory(int(ret.GetValue(), 16), 2**20, error)
184185
if not error.Success():
185-
print error
186+
if printErrors:
187+
print error
186188
return None
187189
else:
188190
ret = json.loads(ret)

0 commit comments

Comments
 (0)