cargo-call-stack 源码解析指南:用 nom 手写 LLVM IR 解析器,构建全程序调用图
cargo-call-stack 源码解析指南用 nom 手写 LLVM IR 解析器构建全程序调用图【免费下载链接】cargo-call-stackWhole program static stack analysis项目地址: https://gitcode.com/gh_mirrors/ca/cargo-call-stackcargo-call-stack是一个 Rust 编写的全程序静态栈使用分析工具它最核心的引擎就是一个用nom组合子库手写的 LLVM IR 解析器。工具先用 nightly 编译器生成 LLVM IR.ll文本再用这个解析器把每个函数定义、调用语句读成内存数据结构最终借助petgraph组装出全程序调用图输出给 Graphviz 渲染。本文带你潜入 Cargo.toml 声明的nom 7.1.3之下看看这个不到 2000 行的解析器是如何分层的、有哪些巧妙和偷懒的设计。为什么不用现成的解析库先看工具的数据流水线cargo nightly call-stack以 fat LTO 重新构建你的程序拿到合并后的 LLVM IR 文本src/ir.rs的入口函数parse()把整篇 IR 解析为VecItem从Item中抽取函数名与签名从函数体中抽取调用边调用边装入petgraph有向图输出.dot文件为什么不直接用inkwell或反汇编二进制因为工具依赖的符号表、-Z stack-sizes信息都以文本形式存在而.ll文件恰好是结构非常规则的文本——手写一个够用的解析器比引入重量级 LLVM 绑定更轻、更可控。这也是本项目最值得关注的设计决策它不需要解析完整的 LLVM IR只需要解析出构建调用图所需的最小子集。解析器分层设计Item → Define → Stmt解析器按 IR 的结构分成三个模块层级关系一目了然模块职责关键类型src/ir.rs顶层入口、基础词法解析parse()、FnSigsrc/ir/item.rs顶层项行级结构Item枚举11 个变体src/ir/define.rs函数定义与函数体内语句Define、Stmtsrc/ir/ty.rs类型系统Type枚举Item枚举item.rs覆盖了 IR 文件的全部顶层结构Alias、Global、Type、Define、Declare、Metadata、ModuleAsm等。顶层item()解析器就是对这些解析函数的一次alt分支尝试pub fn item(i: str) - IResultstr, Item { alt(( comment, source_filename, target, type_, global, alias, map(super::define::parse, Item::Define), declare, attributes, metadata, module_asm, ))(i) }真正有价值的是Define变体。函数体内Stmt枚举define.rs只保留了 7 种语句其中对调用图分析至关重要的是这三种DirectCall(str)—— 直接调用直接给出被调函数名一条确定的边IndirectCall(FnSig)—— 间接调用函数指针、trait 对象动态分发只给出签名Asm(str)—— 内联汇编LLVM 的栈分析对它失明工具需要另行处理也就是说解析阶段就已经完成了降噪解析器只关心会形成调用边的语句其余语句统统归入Stmt::Other丢弃。手写 nom 解析器的几个关键技巧1. 用有意的失败划清词法边界attribute解析器ir.rs处理internal、fastcc等函数属性时遇到double、float、bitcast、alias这类关键词会故意返回错误// have this branch always error because this is not an attribute but part of a type double | float | void | ptr { return Err(nom::Err::Error(error_position!(i, ErrorKind::Switch))); }这样alt组合子会自动回退让类型解析器或语句解析器接手——用解析失败代替显式判断是 nom 中处理词法歧义的惯用手法。2. 够用就好的快捷跳过解析器大量使用not_line_ending直接吞掉整行剩余内容例如declare遇到llvm.开头的内建函数item.rsif name.starts_with(llvm.) { // llvm intrinsic; we dont care about these let i not_line_ending(i)?.0; Ok((i, Item::Declare(Declare { name, sig: None }))) }内建函数不会出现在调用图里所以整行跳过签名记为None。这种局部精确、全局粗略的取舍是嵌入式小工具写解析器的典型思路——不为完备性买单只为下游需求买单。3. 宽松匹配loosely_equal应对类型信息丢失Rust 有u32但 LLVM 只有无符号整数i32新版 LLVM 还使用不透明指针ptr把fn f(x: i32)和impl Foo { fn f(self) }都压成fn(ptr) - i1。因此Type不能简单比较而是实现了loosely_equal()ty.rspub fn loosely_equal(self, other: Self) - bool { match (self, other) { (Self::OpaquePointer, Self::OpaquePointer) true, (Self::OpaquePointer, Self::Pointer(_)) true, (Self::Pointer(_), Self::OpaquePointer) true, // ... } }这正是工具处理间接调用时的核心逻辑把IndirectCall(FnSig)与所有已解析函数的签名做宽松比较把签名兼容的函数全部连边。代价是可能出现多余边详见 README.md 的 Lossy type information 章节收益是不依赖 Rust 类型信息也能工作。4. 精确的报错定位parse()ir.rs把 nom 返回的失败偏移量换算回行号再报错而不是抛出一个无法定位的偏移值——毕竟.ll文件动辄上万行。5. 用真实 IR 片段做测试src/ir/define/目录下有 11 个真实编译器输出的测试文件parse1.ll 到 parse11.ll覆盖内联汇编、间接调用、packed struct 等边缘场景。写解析器时来自真实编译器的测试样例比手写字符串可靠得多。从调用边到全程序调用图解析完成后工具把每条Stmt翻译成图论操作DirectCall连一条确定边IndirectCall按loosely_equal向所有签名匹配的函数连边再结合-Z emit-stack-sizes提供的每个函数本地栈用量做全图最大栈使用量计算最后输出 dot 格式。以示例程序为例工具产出的全程序调用图如下每个节点同时标注local与max栈用量图中Reset同时调用main和DefaultPreInit这正是解析器从define体里抽出的DirectCall边。给新手的可借鉴清单✅组合子思维tag/char拼词法alt/many0/separated_list0/delimited搭结构解析器就是可组合的小函数✅为下游需求裁剪文法不解析完整 IR只保留调用图所需的最小子集用not_line_ending大胆跳过✅失败也是信息用故意返回错误引导alt回退解决词法歧义✅测试用真实输入保存真实编译器输出作为回归测试语料如果你想继续深挖建议按 src/ir.rs → src/ir/item.rs → src/ir/define.rs → src/ir/ty.rs 的顺序通读源码再跑一遍 tests/firmware.rs 的固件级集成测试即可完整复现文本 IR → 全程序调用图的全过程。【免费下载链接】cargo-call-stackWhole program static stack analysis项目地址: https://gitcode.com/gh_mirrors/ca/cargo-call-stack创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

5GB 显存也能跑:ComfyUI-WanVideoWrapper 用 WanVideo 做 AI 视频生成的完整上手指南

5GB 显存也能跑:ComfyUI-WanVideoWrapper 用 WanVideo 做 AI 视频生成的完整上手指南

5GB 显存也能跑:ComfyUI-WanVideoWrapper 用 WanVideo 做 AI 视频生成的完整上手指南 【免费下载链接】ComfyUI-WanVideoWrapper 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-WanVideoWrapper ComfyUI-WanVideoWrapper 是一个 ComfyUI 视频插…

2026/8/23 11:19:31 阅读更多 →
Cookie跨域共享实战:子域名与代理服务器两种方案详解

Cookie跨域共享实战:子域名与代理服务器两种方案详解

1. 从一次真实的跨域登录失败说起最近在重构一个前后端分离的项目时,遇到了一个典型的“登录状态丢失”问题。前端应用部署在https://app.example.com,而后端API服务在https://api.example.com。用户在前端登录,后端成功验证并返回了包含用户…

2026/8/23 11:18:30 阅读更多 →
AI时代招聘变革:从技能考核到交付能力评估

AI时代招聘变革:从技能考核到交付能力评估

1. 招聘市场变革:从技能考核到AI交付能力 2026年的春招季已经悄然拉开帷幕,但今年的招聘风向标发生了根本性转变。作为连续五年参与校招面试的技术负责人,我明显感受到企业评估候选人的标准正在从传统的"你会什么编程语言/框架"转向…

2026/8/23 11:18:30 阅读更多 →

最新新闻

从CCPC网络赛重赛看高并发在线判题系统架构与防作弊设计

从CCPC网络赛重赛看高并发在线判题系统架构与防作弊设计

1. 从“网络赛重赛”说起:一次技术竞赛的非常规复盘 2021年CCPC网络赛的重赛,对于当年参赛的选手、教练以及赛事组织方而言,都是一个绕不开的话题。它不仅仅是一次简单的比赛延期或重新举办,其背后折射出的,是大型在线…

2026/8/23 11:56:46 阅读更多 →
Lakehouse智能体优化:以数据为中心解决AI Agent技能问题

Lakehouse智能体优化:以数据为中心解决AI Agent技能问题

1. 从“技能问题”到数据驱动:Lakehouse智能体的优化新范式最近在跟几个做数据平台和AI应用落地的朋友聊天,大家普遍有个共识:现在搞AI Agent(智能体)项目,最常听到的抱怨不是模型不够强,也不是…

2026/8/23 11:56:46 阅读更多 →
用unicode-segmentation的GraphemeCursor实现双向随机访问:流式文本分段实战指南

用unicode-segmentation的GraphemeCursor实现双向随机访问:流式文本分段实战指南

用unicode-segmentation的GraphemeCursor实现双向随机访问:流式文本分段实战指南 【免费下载链接】unicode-segmentation Grapheme Cluster and Word boundaries according to UAX#29 rules 项目地址: https://gitcode.com/gh_mirrors/un/unicode-segmentation …

2026/8/23 11:56:46 阅读更多 →
一键部署最强Bandizip:脚本自动化实现无广告完整右键菜单

一键部署最强Bandizip:脚本自动化实现无广告完整右键菜单

你肯定遇到过这种情况:下载了一个压缩包,右键点击,菜单里弹出一堆你根本不认识的压缩软件选项,有的图标模糊,有的功能残缺,有的甚至带着烦人的广告弹窗。你只是想快速解压一个文件,却要先在一堆…

2026/8/23 11:56:46 阅读更多 →
如何实现用户自动认证:Microsoft 365 Agents SDK Auto Sign-in OAuth 完整指南

如何实现用户自动认证:Microsoft 365 Agents SDK Auto Sign-in OAuth 完整指南

如何实现用户自动认证:Microsoft 365 Agents SDK Auto Sign-in OAuth 完整指南 【免费下载链接】Agents The Microsoft 365 Agent SDK simplifies building full stack, multichannel, trusted agents for platforms including M365, Teams, Copilot Studio, and We…

2026/8/23 11:56:46 阅读更多 →
Vue3与TypeScript全栈面试实战解析

Vue3与TypeScript全栈面试实战解析

1. 项目概述 作为一名经历过多次技术面试的Java全栈开发者,最近我完成了一次以Vue3为核心的前端技术面试。这次经历让我深刻认识到,即使对于有后端经验的开发者来说,现代前端框架的深度掌握同样至关重要。本文将完整复盘这次技术面试的全过程…

2026/8/23 11:55:45 阅读更多 →

日新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/23 0:00:50 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/23 0:00:50 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/23 0:00:50 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/23 0:00:50 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/23 0:00:50 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/23 0:00:50 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/22 18:08:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/22 7:31:03 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →