【问题标题】:How do I exclude java standard libraries from call graphs generated by Soot?如何从 Soot 生成的调用图中排除 java 标准库?
【发布时间】:2020-05-11 17:40:26
【问题描述】:

我目前正在开发一个自动代码文档工具。为此,我使用 Soot 来构建调用图。然而,Soot 似乎在这个调用图中包含了标准的 java 库。这当然是不可取的,因为我只对要为其生成文档的程序的实际类感兴趣。

这是我用来测试调用图的程序:

    public static void main(String[] args) throws FileNotFoundException {

        List<String> argsList = new ArrayList<String>(Arrays.asList(new String[0]));
        argsList.addAll(Arrays.asList(new String[]{
            "-w",
            "-no-bodies-for-excluded",
            "-process-dir",
            args[1], //directory with the java files
            "-src-prec",
            "java",
            "-main-class",
            args[2] //main class
        }));

        String[] trueArgs = argsList.toArray(new String[0]);
        Main.v().run(trueArgs);
        CallGraph cg = Scene.v().getCallGraph();
        visit(cg , Scene.v().getEntryPoints().get(0));
    }

使用以下函数迭代调用图(取自this question):

    private static void visit(CallGraph cg, SootMethod method) {
          String identifier = method.getSignature();
          visited.put(method.getSignature(), true);
          dot.drawNode(identifier);
          // iterate over unvisited parents
          Iterator<MethodOrMethodContext> ptargets = new Sources(cg.edgesInto(method));
          if (ptargets != null) {
            while (ptargets.hasNext()) {
                SootMethod parent = (SootMethod) ptargets.next();
                if (!visited.containsKey(parent.getSignature())) visit(cg, parent);
            }
          }
          // iterate over unvisited children
          Iterator<MethodOrMethodContext> ctargets = new Targets(cg.edgesOutOf(method));
          if (ctargets != null) {
            while (ctargets.hasNext()) {
               SootMethod child = (SootMethod) ctargets.next();
               dot.drawEdge(identifier, child.getSignature());
               System.out.println(method + " may call " + child);
               if (!visited.containsKey(child.getSignature())) visit(cg, child);
            }
          }
    }

但是,在测试时,我一直在记录此类呼叫:

[...]
<callgraphs.A: void <init>()> may call <java.lang.Object: void <init>()>
<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.Runnable)> may call <java.lang.Object: void <clinit>()>
<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.String)> may call <java.lang.Object: void <clinit>()>
<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.String)> may call <java.lang.Object: void <init>()>
<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.String)> may call <java.lang.Thread: void init(java.lang.ThreadGroup,java.lang.Runnable,java.lang.String,long)>
<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.String)> may call <java.lang.Object: void <init>()>
[...]

随后是 java 库之间的大量调用。

有没有办法让 Soot 直接忽略标准的 java 库?

【问题讨论】:

    标签: java static-analysis call-graph soot


    【解决方案1】:

    好的,我找到了解决办法。

    我们只是抑制来自 java 包中的类的 visit 调用。

    所以通过使用child.isJavaLibraryMethod()来检查它是否来自java包。

    如果它来自 java 包,我们根本不使用该类调用 visit,因此通过添加对父子调用的检查并抑制输出,我们得到正确的调用图。 (作为奖励,它更快,因为您不再遍历 java 库。

    所以代码改为:

    private static void visit(CallGraph cg, SootMethod method) {
              String identifier = method.getSignature();
              visited.put(method.getSignature(), true);
              dot.drawNode(identifier);
              // iterate over unvisited parents
              Iterator<MethodOrMethodContext> ptargets = new Sources(cg.edgesInto(method));
              if (ptargets != null) {
                while (ptargets.hasNext()) {
                    SootMethod parent = (SootMethod) ptargets.next();
                    if (!visited.containsKey(parent.getSignature()) && !parent.isJavaLibraryMethod()) visit(cg, parent);
                }
              }
              // iterate over unvisited children
              Iterator<MethodOrMethodContext> ctargets = new Targets(cg.edgesOutOf(method));
              if (ctargets != null) {
                while (ctargets.hasNext()) {
                   SootMethod child = (SootMethod) ctargets.next();
                   dot.drawEdge(identifier, child.getSignature());
                   if (!child.isJavaLibraryMethod())System.out.println(method + " may call " + child);
                   if (!visited.containsKey(child.getSignature()) && !child.isJavaLibraryMethod()) visit(cg, child);
                }
              }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-08
      • 2016-12-11
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多