Add support for conveniently tracing imported functions

This commit is contained in:
Ole André Vadla Ravnås
2015-09-25 20:42:03 +02:00
parent 4de31ce812
commit 0a0e9bddce
+74 -6
View File
@@ -48,6 +48,11 @@ class TracerProfileBuilder(object):
'offset': int(m.group('offset'), base=16)
}))
def include_imports(self, *module_name_globs):
for m in module_name_globs:
self._spec.append(('include', 'imports', m))
return self
def include_objc_method(self, *function_name_globs):
for f in function_name_globs:
match = re.search(r"([+*-])\[(\S+)\s+(\S+)\]", f)
@@ -149,6 +154,10 @@ function resolve(spec) {
if (operation === 'include')
workingSet = includeRelativeFunction(param, workingSet);
break;
case 'imports':
if (operation === 'include')
workingSet = includeImports(param, workingSet);
break;
case 'objc_method':
if (operation === 'include')
workingSet = includeObjCMethod(param, workingSet);
@@ -255,6 +264,29 @@ function includeRelativeFunction(func, workingSet) {
return workingSet;
}
function includeImports(pattern, workingSet) {
const modules = [];
if (pattern === null) {
modules.push(allModules()[0]);
} else {
const mm = new Minimatch(pattern);
for (let module of allModules()) {
if (mm.match(module.name)) {
modules.push(module);
break;
}
}
}
for (let module of modules) {
const functions = allFunctionImports(module);
for (let func of functions)
workingSet[func.address.toString()] = func;
}
return workingSet;
}
let cachedObjCState = null;
function includeObjCMethod(method, workingSet) {
if (!ObjC.available)
@@ -386,27 +418,59 @@ function getObjCState() {
let cachedModules = null;
function allModules() {
if (cachedModules === null)
if (cachedModules === null) {
cachedModules = Process.enumerateModulesSync();
cachedModules._idByPath = cachedModules.reduce((mappings, module, index) => {
mappings[module.path] = index;
return mappings;
}, {});
}
return cachedModules;
}
function allFunctionImports(module) {
if (!module.hasOwnProperty('_cachedFunctionImports')) {
const moduleIdByPath = allModules()._idByPath;
module._cachedFunctionImports = Module.enumerateImportsSync(module.path)
.filter(isResolvedFunctionImport)
.map(imp => {
const value = {
name: imp.name,
address: imp.address
};
if (imp.hasOwnProperty('module')) {
const moduleId = moduleIdByPath[imp.module];
if (moduleId !== undefined) {
value.module = moduleId;
}
}
return value;
});
}
return module._cachedFunctionImports;
}
function allFunctionExports(module) {
if (!module.hasOwnProperty('_cachedFunctionExports')) {
const moduleId = allModules().indexOf(module);
module._cachedFunctionExports = Module.enumerateExportsSync(module.path)
.filter(isFunctionExport)
.map(e => {
e.module = moduleId;
return e;
.map(exp => {
exp.module = moduleId;
return exp;
});
}
return module._cachedFunctionExports;
}
function isFunctionExport(e) {
return e.type === 'function';
function isResolvedFunctionImport(imp) {
return imp.type === 'function' && imp.hasOwnProperty('address');
}
function isFunctionExport(exp) {
return exp.type === 'function';
}
@@ -1386,6 +1450,10 @@ def main():
type='string', action='callback', callback=process_builder_arg, callback_args=(pb.exclude,))
parser.add_option("-a", "--add", help="add MODULE!OFFSET", metavar="MODULE!OFFSET",
type='string', action='callback', callback=process_builder_arg, callback_args=(pb.include_relative_address,))
parser.add_option("-T", "--include-imports", help="include program's imports",
action='callback', callback=process_builder_arg, callback_args=(pb.include_imports,))
parser.add_option("-t", "--include-module-imports", help="include MODULE imports", metavar="MODULE",
type='string', action='callback', callback=process_builder_arg, callback_args=(pb.include_imports,))
parser.add_option("-m", "--include-objc-method", help="include OBJC_METHOD", metavar="OBJC_METHOD",
type='string', action='callback', callback=process_builder_arg, callback_args=(pb.include_objc_method,))
self._profile_builder = pb