关于 ohos-dev-distributed-cpp-callgraph-analysis
用于检查 OpenHarmony C++ 调用链和数据传递路径是否完整的技能。它结合 LSP、源码证据、边分类和覆盖矩阵;可选脚本仅用于发现候选边,不能单独证明完整性。
主要功能
- 01定义入口、目标行为和分析范围
- 02结合 LSP、源码及构建信息发现调用边
- 03分类直接、虚拟、回调、IPC 等边
- 04用调用链表整理证据
- 05检查代码各层的修改覆盖情况
- 06可选地从构建产物发现候选边
适用场景
- 01追踪数据字段在 OpenHarmony 子系统间的传递
- 02评估变更是否覆盖相关调用路径
- 03调查未明确的回调、IPC 或动态加载路径
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ openharmonyinsight/ openharmony-skills --skill ohos-dev-distributed-cpp-callgraph-analysis安装后在 Claude Code 中输入/ohos-dev-distributed-cpp-callgraph-analysis确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
ohos_callgraph.pyREADME.mdevals/evals.jsonREADME.mdreferences/lsp-bootstrap.mdscripts/setup_lsp.pytests/test_ohos_callgraph.pytest_setup_lsp.py详细介绍
OpenHarmony 调用链完整性分析
此技能包含一个决策层和可选的工具支持:
- Agent 工作流:唯一能够判断调用链完整性的层。它使用 LSP/源码证据、边分类和覆盖矩阵。
- 可选的产物回退方案:当 LSP/源码证据存在缺口或 LSP 不可用时,
ohos_callgraph.py会从构建产物中发现候选直接调用边,并尽力提供 vtable/dlopen 提示。
不要仅凭脚本输出就声称调用链完整。
引导配置仓库范围的 LSP
开始分析前,检查是否已有基于正确 OpenHarmony 产品编译上下文的可用 LSP/MCP 工具。有则使用。
如果 LSP 缺失或解析的仓库不正确,请阅读
references/lsp-bootstrap.md,并在分析前按其中说明操作。引导配置属于可选支持,而非前置条件:如果设置或冒烟测试失败,请记录 LSP 不可用或不完整,并继续使用源码、构建、符号、辅助工具和运行时证据进行分析。
如果 clangd 在某个文件上极其缓慢(CPU 占用率达到 100% 且持续数分钟),该文件可能未包含在经过筛选的 compile_commands.json 中。对于 Claude 客户端,请在设置期间传入 --install-hook,以安装 Claude PreToolUse 自动修复钩子。对于 Codex 或其他客户端,请使用
references/lsp-bootstrap.md 中“文件不在 compile_commands.json 中”一节所述的手动修复方法。
必需的工作流
1. 定义分析目标
使用工具前,请说明:
- 入口点或事件路径,例如
OnRemoteRequest、HandleEvent或特定子系统的入口函数。 - 目标数据或行为,例如传播的字段、路由决策或状态转换。
- 要纳入的范围边界:客户端/服务端、IPC、回调、虚拟接口、dlopen/dlsym 实现、生成代码和测试。
- 有意排除的范围边界及其原因。
如果其中任何一项未知,请先检查代码,再作出有界假设。不要跳过此步骤。
2. 发现候选边
按以下顺序使用证据来源:
- LSP / clangd:首选的静态来源,用于查找定义、声明、引用、调用层级、候选重写项以及支持宏的符号位置。
- 源码搜索:使用
rg查找 LSP 不易建模的框架模式,例如事务码、监听器注册、LoadLibrary<>、dlsym和生成文件名。 - 构建图和符号工具:使用 GN/Ninja、
llvm-nm、llvm-readelf、llvm-objdump和llvm-cxxfilt查找库、导出项、链接边和生成产物。 - 仅在需要时使用辅助脚本:当 LSP/源码/构建证据仍存在无法解释的边、需要产物级确认,或 LSP 不可用/不完整时,使用
ohos_callgraph.py发现 IR 级候选直接边,并尽力提供 vtable/dlopen 提示。 - 运行时跟踪:当静态证据无法唯一确定虚调用、回调、IPC 或 dlopen/dlsym 边时,使用日志、插桩或符号化跟踪。
LSP 是获取语言级 C++ 事实的首选,但不足以确定运行时绑定或 OpenHarmony 框架协议。
当 LSP/clangd 可用时,将其作为以下操作的主要途径:
definition/declarationreferencescall hierarchy中的传入/传出调用- 重写项和实现候选项
- 宏展开后的符号位置
不要仅为重复 LSP 得到的直接调用结果而运行辅助脚本。只有当脚本能回答不同问题时才运行,例如“此编译产物是否包含候选边?”或“LSP 无法解析此路径时有哪些候选项?”
当 LSP 不可用或不完整时,请在证据表中说明,并回退到源码搜索以及构建/符号证据。
辅助脚本
资源检查:运行辅助脚本前,使用 find <obj_dir> -name '*.o' | grep <repo-filter> | wc -l 估算 bitcode 文件数量。如果文件数超过约 200 个,请缩小 --repo 过滤范围,或改用 LSP/源码证据。每个文件需要调用两次 LLVM 工具(每次约 1-2 秒),因此处理 200 个文件可能需要 5-10 分钟。
辅助脚本的必要调用形式。调用脚本前,Agent 必须确定源码树和仓库过滤条件,然后显式传入:
SCRIPT=/path/to/skills/ohos-dev-distributed-cpp-callgraph-analysis/ohos_callgraph.py
python3 "$SCRIPT" <entry-function> \
--oh-root <openharmony-source-root> \
--product <product-name> \
--repo <repo-filter> \
--depth 4 \
--skip-prefix "Subsystem::LogHelper" --skip-prefix "Subsystem::TimeUtil"
省略 --skip-prefix 可使用内置默认值(HiLog、std::h 等)。传入一个或多个 --skip-prefix 可完全覆盖这些默认值,改用针对特定子系统的前缀。
反向查找直接调用者:
python3 "$SCRIPT" <target-function> \
--oh-root <openharmony-source-root> \
--product <product-name> \
--repo <repo-filter> \
--reverse \
--depth 3
辅助脚本输出的是候选列表。每条重要边仍需源码证据。 在反向模式下,辅助脚本只会反向查找直接调用边,不会反向查找 vtable 或 dlopen/dlsym 提示边。
3. 对每条边进行分类
必须对每条调用链边进行分类:
| 类型 | 所需证据 |
|---|---|
direct | 优先使用 LSP 调用层级/引用;包含调用者行号以及被调用者的定义或声明 |
virtual | 优先使用 LSP 重写候选;包含接口调用位置、候选重写项,以及已知的分发原因 |
callback | 注册位置和调用位置;LSP 可以定位符号,但通常无法证明从注册到调用的流程 |
ipc | 代理写入、存根读取、事务代码和服务处理程序 |
dlopen/dlsym | 加载位置、库/符号名称、工厂或函数指针的使用;必要时通过符号或跟踪确认 |
macro/generated | 优先使用能识别宏的 LSP 位置;包含可证明该边的生成源码或展开后的目标 |
unknown | 证据缺口;无法据此声称内容完整 |
对于 virtual、callback、IPC 和 dlopen/dlsym 边,列出所有相关候选项,或明确说明为何只有一个候选项适用。
4. 构建证据表
输出包含以下列的表格:
| 调用者 | 被调用者/候选项 | 边类型 | 证据来源 | 证据 | 置信度 | 是否需要变更 | 变更状态 |
|---|
规则:
Evidence Source是以下一个或多个值:lsp、source、build、symbol、script、runtime或manual。Evidence必须包含文件路径和行号。Confidence为confirmed、candidate或unknown。Needs Change说明目标数据或行为为何必须经过这条边。Change Status为done、missing、not needed或unknown。- 仅凭
script证据,不能将非直接边标记为confirmed。
不要将多种边类型合并到同一行。
5. 构建修改覆盖矩阵
对于数据传播变更(例如必须在多个层之间传递的字段),请检查每个适用的层面:
| 层面 | 检查内容 | 静态证据 | 运行时证据 | 状态 |
|---|---|---|---|---|
| 函数签名 | 参数或对象是否携带目标数据 | LSP 定义/声明或源代码行 | 可选 | |
| 调用参数 | 调用方是否传递正确的值,而非默认值或过时值 | LSP 调用层次结构/引用或源代码行 | 可选 | |
| 事件/对象字段 | 字段是否正确设置、复制、克隆和重置 | 源代码/LSP 字段引用 | 可选 | |
| IPC 代理/存根 | Parcel 写入/读取顺序和事务兼容性 | 源代码事务和 Parcel 证据 | 如果有歧义,则提供跟踪/日志 | |
| 服务分发 | 服务端是否接收并使用该值 | 源代码/LSP 处理程序路径 | 如果有歧义,则提供跟踪/日志 | |
| 虚函数重写 | 所有可达的重写是否都接受或推导该值 | LSP 重写候选项和源代码证据 | 如果静态分发不唯一,则必需 | |
| 回调流程 | 注册和调用是否都保留该值 | 源代码注册/调用证据 | 如果注册到调用的流程有歧义,则必需 | |
| dlopen/dlsym 实现 | 加载的实现是否处理该值 | 源代码 + 符号/构建证据 | 如果加载目标取决于运行时,则必需 | |
| 生成的代码 | 生成的包装器和 ABI 层是否保留该值 | 生成的源代码或构建产物证据 | 可选 | |
| 测试 | 单元/系统测试是否至少覆盖一条有代表性的路径和边界情况 | 测试源代码证据 | 可用时提供测试执行结果 |
最终答案必须说明哪些行已完成、缺失或未知。
6. 判断完整性
使用以下标签:
- 完整:所有相关的已确认边和候选边均标记为
done或not needed,且未知项已解决或明确排除在范围之外。 - 不完整:至少有一个必需的边或层面标记为
missing。 - 无法证明:仍有重要边标记为
unknown,或者仅凭静态证据无法确定影响结论的运行时绑定边。
辅助脚本的范围
ohos_callgraph.py 是在检查 LSP/源代码之后可选使用的产物回退方案:
- 来自
opt --print-callgraph的直接 IR 调用边 - 基于 LLVM IR 元数据尽力提供的虚表接口提示
- 基于常见
LoadLibrary<>/CreateInstance模式尽力提供的 dlopen 提示 - 仅反向查找直接调用方;反向模式不包含虚表或 dlopen/dlsym 提示边
局限性:
- 它无法证明所有可能的 C++ 调用。
- 它无法将运行时虚分发解析为唯一的重写实现。
- 它无法证明回调、函数指针或
std::function的目标。 - 它无法证明 IPC 参数传播。
- 它无法证明字段传播。
--name-keyword仅检查反混淆后的函数名和直接子函数名,作为粗略提示;它不会检查 C++ 参数名、调用参数、成员访问、局部变量或 IPC 序列化。 - 如果构建产物过时、缺少位码、优化方式不同或外部工具失败,它可能会遗漏边。
仅将辅助脚本用作证据工作流中的候选项发现工具。如果 LSP/源代码证据已覆盖相关直接调用,且不需要产物级确认,则跳过此脚本。
LSP 指引
仅当 LSP/clangd 使用的编译上下文适用于正在审查的 OpenHarmony 产品时,才将其作为证据。如果仓库缺少 compile_commands.json,或 clangd 无法解析 include/宏,则应将 LSP 证据标记为不完整,并改用源码/构建证据。
当 LSP 不可用且环境允许进行配置时,应先遵循引导仓库范围的 LSP,再考虑其他方式。若能生成仓库范围的数据库,就不要直接使用产品范围的编译数据库;产品数据库可能有数 GB,会造成不必要的索引开销。
建议执行的 LSP 证据检查:
- 对于直接函数调用,使用调用点的出站调用层次结构或转到定义,然后记录调用方和被调用方所在的文件行。
- 对于反向分析,使用入站调用层次结构和引用,然后手动验证调用点。
- 对于虚调用,使用实现/重写查询列出候选项。除非构造/注册/源码规则或运行时跟踪能够证明确切目标,否则应将候选项保留为
candidate。 - 对于宏,使用 LSP 获取解析后的符号位置;必要时记录宏或生成的展开源码。
不要仅凭 LSP 确认回调流、IPC 分发或 dlopen/dlsym 目标。
必需的最终回复格式
使用此技能时,结尾必须包含:
- 范围:入口点、目标数据/行为、涵盖的边界。
- 证据表:逐边列出证据来源、证据、置信度和状态。
- 覆盖矩阵:列出修改面、静态证据、运行时证据和状态。
- 结论:
Complete、Incomplete或Not provable,并准确列出缺失或未知的项目。
如果无法检查必需的边界,请说明原因并将其标记为 unknown。
示例:MMI 子系统
分析多模态输入(MMI)子系统时,常见的分析目标包括:
- 入口点:
HandleMouseEvent、UpdateMouseTarget、OnRemoteRequest - 传播字段:
groupId、displayId、指针目标路由、设备绑定 - 跳过前缀:
OHOS::MMI::FormatLog、OHOS::MMI::GetSysClockTime、OHOS::MMI::InnerFunction(通过--skip-prefix传入) - 关键边界:通过
MultimodalInputConnectStub进行客户端/服务端 IPC、EventDispatchHandler回调链、InputDeviceManager的 dlopen 加载