Java 调用图的静态分析

Static analysis of Java call graph

提问人:Mark Renouf 提问时间:2/10/2011 最后编辑:Christophe RoussyMark Renouf 更新时间:9/26/2022 访问量:29136

问:

我想做的是扫描一组 Java 类,并跟踪来自抽象类的特定方法的所有方法调用,并在该上下文中构建执行某些操作的所有代码的列表(在本例中,实例化某个类的实例)。我想知道,行号和提供的参数。

我已经开始研究 BCEL,但它似乎没有内置调用图跟踪?我犹豫要不要自己写,因为获得重载、类型签名和多态调度可能很棘手。

我半信半疑地期望存在一个工具或示例代码,但我还没有找到任何东西。真的感觉我即将重新发明一个轮子。但如果我这样做,它将是一个开源轮子,可在 GitHub 上获得 ;-)

PS:你会发现现有的问题“如何生成一个Java调用图”,因为它听起来是一样的,但它根本不是我需要的。

Java 静态分析 调用图

评论

1赞 Anon. 2/10/2011
实际上,似乎公认的答案的第二部分(关于查找所有参考文献)实际上是您想要的。
0赞 Mark Renouf 2/10/2011
我需要作为自动过程的一部分执行此操作的代码。
1赞 Joeblackdev 7/26/2011
Mark,你有没有和 Soot 一起工作过?不幸的是,我没有成功,因为我无法在没有 main 方法的类中成功设置入口点。你是怎么做到的?
0赞 xpt 1/27/2020
嗨,马克,这么多年过去了,你找到可以接受的解决方案了吗?-- 我们可以投你的一票。

答:

2赞 Ira Baxter 3/6/2011 #1

听起来你想要一些提供对抽象语法和完整符号表的访问的东西。然后,对根植于抽象方法的每个实现方法(如符号表所示)的调用图中函数的 AST 进行自定义扫描,使您有机会找到其类型为特定感兴趣类的新操作。

DMS软件再造工具包是一种通用编译器技术,提供解析、AST构建/导航、符号表构建/导航、控制流、数据流和调用图构建等基本服务。DMS 有一个可选的 Java 前端,它提供了一个完整的 Java 解析器,构建了 Java AST 和符号表,并且可以构造调用图。Java 前端还可以读取 .class 文件;你不清楚你是否也想爬进班级文件,寻找信息。

你想要的答案不是现成的。您需要构建一些自定义代码来实现第一段中的想法,但 DMS 可以提供大部分原材料。它没有提供 .class 文件中的太多细节(这些文件主要用于解析源代码中的类型)。

5赞 Eric 3/6/2011 #2

烟灰应该可以让你轻松实现你想要的东西:http://www.sable.mcgill.ca/soot/

它可以全自动构建精确的呼叫图。

您可以在此处找到所有必要的文档:http://www.sable.mcgill.ca/soot/tutorial/index.html

此外,还有一个活跃的 Soot 邮件列表。

评论

0赞 Kumar Roshan Mehta 6/2/2014
我从 apk 获得了 jimple,但无法使用命令行构建调用图。需要帮助。
6赞 James from CppDepend Team 10/27/2011 #3

你可以试试 JavaDepend ,它提供了依赖项和指标所需的许多功能,它还提供了一个像 SQL 这样的 CQL 来请求您的代码库。

披露:这是一个商业软件。

6赞 metdos 1/30/2012 #4

您可以将 DoxygenGraphviz 一起使用。它易于安装和使用。

9赞 Georgios Gousios 5/18/2012 #5

您可以使用 java-callgraph 工具套件为 Java 创建足够准确的静态和动态调用图。

0赞 Christophe Roussy 3/10/2020 #6

对于“最近的”Eclipse 安装(相对于问题),请参阅 Certiv CallGraph

CallGraph 支持对程序调用关系和流排序进行图形分析。还支持探索扩展的类继承层次结构。

调用路径分析和类层次结构解析是使用 JDT 平台搜索和调用层次结构机制执行的。

序列图是通过对任何选定类或方法的 JDT 平台 AST 的静态分析生成的。

使用 Zest 作为图形可视化引擎。

您可以通过 Eclipse 市场安装它。我没有参与制作这个。 您不能缩小,这不是很实用,但支持序列图,这很好,允许根据需要打开/关闭节点以进一步挖掘。

要求:

Eclipse 4.6 (Neon) on Java 8 VM
Eclipse Zest Visualization Toolkit 1.7

Eclipse 公共许可证 v1.0

0赞 Adrninistrator 7/6/2021 #7

您可以看到:https://github.com/Adrninistrator/java-all-call-graph/blob/main/README-en.md

输出示例:

  • 向上
org.mybatis.spring.SqlSessionUtils:lambda$closeSqlSession$6(org.apache.ibatis.session.SqlSession)
[0]#org.mybatis.spring.SqlSessionUtils:lambda$closeSqlSession$6(org.apache.ibatis.session.SqlSession)
[1]#  org.mybatis.spring.SqlSessionUtils:closeSqlSession(org.apache.ibatis.session.SqlSession,org.apache.ibatis.session.SqlSessionFactory)
[2]#    org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor:invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[])    !entry!

org.mybatis.spring.SqlSessionUtils:lambda$getSqlSession$0()
[0]#org.mybatis.spring.SqlSessionUtils:lambda$getSqlSession$0()
[1]#  org.mybatis.spring.SqlSessionUtils:getSqlSession(org.apache.ibatis.session.SqlSessionFactory) !entry!
[1]#  org.mybatis.spring.SqlSessionUtils:getSqlSession(org.apache.ibatis.session.SqlSessionFactory,org.apache.ibatis.session.ExecutorType,org.springframework.dao.support.PersistenceExceptionTranslator)
[2]#    org.mybatis.spring.SqlSessionUtils:getSqlSession(org.apache.ibatis.session.SqlSessionFactory)   !entry!
[2]#    org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor:invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[])    !entry!
  • 向下
org.mybatis.spring.SqlSessionFactoryBean:scanClasses(java.lang.String,java.lang.Class)
[0]#org.mybatis.spring.SqlSessionFactoryBean:scanClasses(java.lang.String,java.lang.Class)
[1]#  org.springframework.util.StringUtils:tokenizeToStringArray(java.lang.String,java.lang.String)
[1]#  org.springframework.util.ClassUtils:convertClassNameToResourcePath(java.lang.String)
[1]#  org.springframework.core.io.support.ResourcePatternResolver:getResources(java.lang.String)
[1]#  org.springframework.core.type.classreading.MetadataReaderFactory:getMetadataReader(org.springframework.core.io.Resource)
[1]#  org.springframework.core.type.classreading.MetadataReader:getClassMetadata()
[1]#  org.springframework.core.type.ClassMetadata:getClassName()
[1]#  org.apache.ibatis.io.Resources:classForName(java.lang.String)
[2]#    org.apache.ibatis.io.ClassLoaderWrapper:classForName(java.lang.String)
[3]#      org.apache.ibatis.io.ClassLoaderWrapper:getClassLoaders(java.lang.ClassLoader)
[3]#      org.apache.ibatis.io.ClassLoaderWrapper:classForName(java.lang.String,java.lang.ClassLoader[])
[1]#  org.mybatis.spring.SqlSessionFactoryBean:lambda$scanClasses$19(org.springframework.core.io.Resource,java.lang.Throwable)
0赞 Gajanand Jha 9/26/2022 #8

一个很棒的 git 存储库就在这里:

https://github.com/gajanandjha/Java-Call-Tree-Generator

它生成 Java 进程中所有线程的调用树,然后 repo README 注释为我们提供了一些 Unix 魔术命令来获取我们需要的线程跟踪,并生成一个简单的网页,其中包含线程在流中访问过的所有方法的树视图。