上一次,我们讲述了如何使用wala对类进行最简单的分析,这次将使用wala工具,进行静态切片分析。
如果对切片不是很熟悉,可以直接搜索 程序切片,有很多关于切片技术的讲解,这里不在讲述。
步入主题:
首先,在上一次ClassHierarchy cha的基础上,需要构建入口点,分析选项,反射机制,如下所示:
Iterable<Entrypoint> entrypoints =Util.makeMainEntrypoints(scope, cha);
AnalysisOptions options = new AnalysisOptions(scope, entrypoints);
options.setReflectionOptions(ReflectionOptions.NONE);
随后,我们需要构建call graph:
// 这里,Util类下有很多builder函数,具体含义我个人也不是很清楚,希望懂的大神可以分享,万分感谢。
CallGraphBuilder<InstanceKey> builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCacheImpl(), cha, scope);
CallGraph cg = builder.makeCallGraph(options, null);
可以使用cg图,加数据流控制流选项直接进行切片,但是这里不建议这样子使用,因为切片是基于sdg图进行的,所以这里先构建sdg图:
// Build sdg
final PointerAnalysis<InstanceKey> pa = builder.getPointerAnalysis();
SDG<?> sdg = new SDG<>(cg, pa, modRef, DataDependenceOptions.REFLECTION, ControlDependenceOptions.NO_EXCEPTIONAL_EDGES, null);
函数重点modRef,需要在加private ModRef<InstanceKey> modRef = ModRef.make(); 其余的参数可以通过eclipse中查看,可以对照wala的源代码进行查看。
构建完sdg图,就可以进行切片分析,wala工具有直接的切片入口,但是调用之前,我们需要知道seed是什么(补充一点,目前我个人所掌握的智能通过函数调用这样的方式得到seed,如果有哪位大神可以使用其他类型的seed,请留言告知,这里万分感谢!!!)。
第一步,创建一个collection,用于存储结果,Collection<Statement> collection = null;
第二步,我们需要知道,seed在哪个函数中,所以,我们要先在cg图里找到哪个节点是对应的函数,
//cg图,函数名,函数所在的类
public CGNode findMethod(CallGraph cg, String Name, String methodCLass) {
if(Name.equals(null) && methodCLass.equals(null))
return null;
//构建 atom(wala中),用来比较CGNode的名字和类
Atom name = Atom.findOrCreateUnicodeAtom(Name);
//迭代cg图
for (Iterator<? extends CGNode> it = cg.iterator(); it.hasNext();) {
CGNode n = it.next();
// 函数名和类名比较
if (n.getMethod().getName().equals(name) &&
n.getMethod().getDeclaringClass().getName().toString().equals(methodCLass)) {
return n;
}
}
Assertions.UNREACHABLE("Failed to find method " + name);
return null;
}
第三步,在CGNode中找到seed
// n是第二步的返回值,methodName是seed的函数名
public Statement findCallTo(CGNode n, String methodName) {
// 函数n的ir,中间表示(和llvm的ir很相似)。
IR ir = n.getIR();
//System.out.println(ir.toString());
//迭代ir中每一条指令,寻找seed
for (Iterator<SSAInstruction> it = ir.iterateAllInstructions(); it.hasNext();) {
SSAInstruction s = it.next();
// 当前指令是调用指令,比较函数名,是否是seed;
if (s instanceof SSAInvokeInstruction) {
SSAInvokeInstruction call = (SSAInvokeInstruction) s;
if (call.getCallSite().getDeclaredTarget().getName().toString().equals(methodName)) {
IntSet indices = ir.getCallInstructionIndices(call.getCallSite());
Assertions.productionAssertion(indices.size() == 1,
"expected 1 but got " + indices.size());
return new NormalStatement(n, indices.intIterator().next());
}
}
}
Assertions.UNREACHABLE("Failed to find call to " + methodName + " in " + n);
return null;
}
第四步,切片分析;
CGNode n = findMethod(cg, callname, callmethodClass);
Statement statement = findCallTo(n, methodName);
//自动导入包即可,slicer还有很多方法,如反向切片,上下文敏感等
collection = Slicer.computeForwardSlice(sdg, statement);
//如果要使用瘦切片
ThinSlicer ts = new ThinSlicer(cg,pa); Collection<Statement> slice = ts.computeBackwardThinSlice ( statement );最后,只需要将得到的collection遍历打印就可以看到结果了
public static void dumpSlice(Collection<Statement> slice) { for (Statement s : slice) { System.err.println(s); } }
本次wala切片使用的心得就写到这里,我这里也是参考了wala官网的例子。
http://wala.sourceforge.net/wiki/index.php/UserGuide:Slicer
以上都是个人使用经验且全部可以运行,如有错误,希望各位大神批评改正,也很期待私信交流。