当前位置:首页 > 技术 > 正文内容

基于静态分析的Java方法调用路径提取与堆栈生成指南

访客 技术 2026年6月2日 1

核心概念与应用场景

在软件静态分析过程中,全量方法调用链通常包含庞大的节点数量,导致分析复杂度急剧上升。在许多实际业务场景中,开发者更关注从起始方法到特定目标方法之间的精确调用路径(即调用堆栈),以及中间经过的节点。

借助 JACG (Java All Call Graph) 等静态分析工具,可以在生成全量调用链的基础上,通过关键字匹配定位目标方法,并提取出从起点到终点的直接或间接调用堆栈。这种机制不仅有助于评估某个方法被调用时的影响范围(向上追溯入口),还能明确某个方法执行时会触发的底层业务操作(向下追踪依赖)。

调用堆栈输出样例解析

生成的调用堆栈文件能够清晰展示方法间的层级关系。以下为典型调用路径的结构示意图:

调用路径结构示意图

向上追溯调用堆栈

当从目标方法(如 DestClass:destfunc)向上查找包含 !entry! 关键字的入口方法时,生成的堆栈文件内容如下:

[0]#DestClass:destfunc()
[1]#  ClassA3:funcA3()	(ClassA3:10)
[2]#    ClassA2:funcA2()	(ClassA2:19)
[3]#      ClassA1:funcA1()	(ClassA1:23)    !entry!

[0]#DestClass:destfunc()
[1]#  ClassB1:funcB1()	(ClassB1:57)    !entry!

[0]#DestClass:destfunc()
[1]#  ClassC2:funcC2()	(ClassC2:31)
[2]#    ClassC1:funcC1()	(ClassC1:9)    !entry!

上述文本对应的调用关系拓扑如下:

向上调用关系拓扑

向下追踪调用堆栈

当从起始方法(如 SrcClass:srcfunc)向下查找包含 ClassA3:funcA3 关键字的底层方法时,生成的堆栈文件内容如下:

[0]#SrcClass:srcfunc()
[1]#  [SrcClass:15]	ClassA1:funcA1()
[2]#    [ClassA1:27]	ClassA2a:funcA2a()
[3]#      [ClassA2b:39]	ClassA3:funcA3()

[0]#SrcClass:srcfunc()
[1]#  [SrcClass:15]	ClassA1:funcA1()
[2]#    [ClassA1:59]	ClassA2b:funcA2b()
[3]#      [ClassA2b:39]	ClassA3:funcA3()

对应的向下调用关系拓扑如下:

向下调用关系拓扑

核心配置与执行机制

调用堆栈的提取依赖于预先生成的全量调用链数据。在执行堆栈生成任务前,需确保相关配置文件已正确设置。

关键配置文件

  • config_db.properties:配置底层数据库连接信息,用于存储和检索调用图数据。
  • method_class_4callee.properties:定义需要向上追溯调用链的起始类或方法。
  • method_class_4caller.properties:定义需要向下追踪调用链的起始类或方法。
  • find_stack_keyword_4ee.properties:向上追溯时,用于匹配目标入口方法的关键字集合。
  • find_stack_keyword_4er.properties:向下追踪时,用于匹配底层依赖方法的关键字集合。

编程方式集成示例

除了通过配置文件驱动,工具也支持在代码中动态构建配置并执行分析任务。

向上追溯堆栈生成

ConfigureWrapper configEnv = new ConfigureWrapper();
configEnv.setOtherConfigSet(OtherConfigFileUseSetEnum.OCFUSE_METHOD_CLASS_4CALLEE, System.class.getCanonicalName());
configEnv.setOtherConfigList(OtherConfigFileUseListEnum.OCFULE_FIND_STACK_KEYWORD_4EE, JACGConstants.CALLEE_FLAG_ENTRY_NO_TAB);

FindCallStackTrace stackTraceFinder = new FindCallStackTrace(true, configEnv);
CallStackFileResult result = stackTraceFinder.find();
if (!result.isSuccess()) {
    throw new RuntimeException("Failed to generate upward call stack.");
}

向下追踪堆栈生成

ConfigureWrapper configEnv = new ConfigureWrapper();
configEnv.setOtherConfigSet(OtherConfigFileUseSetEnum.OCFUSE_METHOD_CLASS_4CALLER, TestBranch1.class.getCanonicalName());
configEnv.setOtherConfigList(OtherConfigFileUseListEnum.OCFULE_FIND_STACK_KEYWORD_4ER, System.class.getCanonicalName());

FindCallStackTrace stackTraceFinder = new FindCallStackTrace(false, configEnv);
CallStackFileResult result = stackTraceFinder.find();
if (!result.isSuccess()) {
    throw new RuntimeException("Failed to generate downward call stack.");
}

输出文件结构与多维格式

文件目录与命名规范

生成的调用堆栈文件默认存放在全量调用链目录下的 _stack 子目录中。若未匹配到关键字,文件则会被移至 _keywords_not_found 目录。文件命名规则遵循 {唯一类名}@{方法名}@{完整方法HASH+长度}.md 的格式,确保唯一性与可追溯性。

多维数据格式支持

通过在 config.properties 中启用 call.graph.gen.stack.other.forms=true,系统可在 _other_forms 目录下生成表格化及汇总维度的数据文件,便于后续导入数据库或进行自动化审计。

表格化堆栈数据示例 (callee_stack_table.md):

调用堆栈在文件中的序号 调用堆栈内部的序号 完整调用方法/被调用方法 调用方法代码行号
000001 1 test.callgraph.multi.TestMulti:test2() 31
000001 2 test.callgraph.implement.AbstractClass1:f2() 0
000001 3 test.callgraph.implement.ChildClass1:f2() 17
000001 4 java.lang.System:exit(int) 0

堆栈汇总数据示例 (callee_stack_summary.md):

调用堆栈在文件中的序号 完整被调用方法 上层完整调用方法 向上通过关键字找到的完整方法 向上通过关键字找到的方法返回类型
000001 java.lang.System:exit(int) test.callgraph.implement.ChildClass1:f2() test.callgraph.multi.TestMulti:test2() void
000002 java.lang.System:exit(int) test.callgraph.implement.ChildClass1:f2() test.callgraph.multi.TestMulti2:test2() void

双向调用链分析(先向上后向下)

在复杂的安全审计或影响面评估场景中,通常需要先向上定位触发目标方法的所有入口点,然后再从这些入口点向下分析其完整的业务执行流。工具提供了专门的双向分析类来支持此类需求。

实现代码

ConfigureWrapper configEnv = new ConfigureWrapper();
String targetMethod = System.class.getCanonicalName() + ":exit(";
String keywordToFind = System.class.getCanonicalName() + ":getProperty(";

configEnv.setOtherConfigSet(OtherConfigFileUseSetEnum.OCFUSE_METHOD_CLASS_4CALLEE, targetMethod);
configEnv.setOtherConfigList(OtherConfigFileUseListEnum.OCFULE_FIND_STACK_KEYWORD_4ER, keywordToFind);

FindCallStackUpAndDown bidirectionalFinder = new FindCallStackUpAndDown(configEnv);
CallStackFileResult result = bidirectionalFinder.find();
if (!result.isSuccess()) {
    throw new RuntimeException("Bidirectional call stack generation failed.");
}

执行上述逻辑后,系统会分别在带有 _upward_downward 后缀的时间戳目录中,输出向上追溯和向下追踪的完整堆栈文件,从而形成闭环的调用影响面分析数据。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。