Skip to content

ARD 阶段工作与论文计划汇报 ​

1. 当前个人研究路线 ​

主要成果分别是:

  1. 面向不同 OS、运行时和真实硬件环境的 ARD 适配与验证;
  2. 从运行信息采集到 History、Observer、Snapshot,再到前端展示的异步状态组织架构。
  3. 以异步函数为主体、同步函数作为运行上下文辅助信息的分层观测机制。

共同回答的是以下几个问题: 大问题:普通调试器难以正确恢复异步函数的连续调用状态。

小问题: 1.异步函数没有足够的身份标识来互相串联(给每一次异步执行建立可靠身份) 2.如何从离散事件恢复连续执行历史(history树) 3.目前调用栈的正确执行函数和状态是什么(snapshot) 4.大量函数中,用户怎么选择自己想查看的异步函数调用子树(observer) 5.怎么利用同步函数串联异步函数的上下文来丰富函数执行链 6.怎么在多个架构平台和OS中适配 7.怎么通过多个证据源共同验证调用链的正确性,以及证据不足时展示unknown

证据作用
静态 Future 分析提供候选关系
poll事件证明真实执行
wake关系证明调度关联
activation信息区分实例
thread/task context避免错误连接

2. 主要工作一:ARD 面向不同 OS 和运行环境的适配 ​

持续进行的第一类工作,是把原有异步调试能力从相对单一的测试环境逐步扩展到不同运行环境。

目前主要涉及:

text
Minimal
   ↓
Embassy
   ↓
Rel4
   ↓
StarryOS
   ↓
K3 COM260 + StarryOS 真板

还有Lilos 已完成 ARM/Cortex-M 环境下的重要适配和异步执行链动态验证;当前可作为跨架构、跨运行时适配的重要历史验证结果,后续计划在最新架构下补充复测。

不同环境之间不是简单替换一个 ELF 文件,它会涉及:

  • native / remote 调试方式差异;
  • x86-64 / RISC-V 参数寄存器和 GDB 行为差异;
  • QEMU / gdbserver / OpenOCD 等不同 remote target;
  • 不同 OS 的源码目录、ELF、DWARF 和 launch 配置;
  • poll 函数发现和 whitelist生成;
  • 不同异步运行环境下的 Future 表达;
  • 真板上的源码路径、断点、单步和符号匹配。

因此这部分工作的重点是在逐步检查 ARD 的异步关系恢复机制是否依赖某一种运行时或某一种实验环境。

前序 2025 年方案的重点仍然是通过 DWARF 静态分析获得 Future 依赖关系,再结合 whitelist 和动态 poll 插桩恢复异步调用关系。

后续的适配工作则更多回答:

当运行环境、架构、调试链和 Future 实现发生变化时,现有异步调试机制是否仍然成立?

因此,这一部分应该更适合作为论文的通用性与外部有效性验证基础。

3. 主要工作二:多重关系验证与History、Observer、Snapshot 三层异步状态架构 ​

3.1 以前的处理方式 ​

前面的异步调试工作已经能够:

text
采集异步信息
    ↓
恢复调用关系
    ↓
生成异步调用树
    ↓
展示结果

但继续采用“采集到什么信息,就直接用于生成和展示当前结果”的方式,会逐渐出现:

历史发生过的关系、用户当前想观察的关系、程序此刻仍然有效的关系,实际上并不是同一个概念。

例如:

text
A
└── B

这条关系可能在程序运行过程中真实发生过。

但是程序继续运行以后:

text
B 已经结束
A 当前正在等待 C

此时:

  • 从历史角度看,A → B 应该继续存在;
  • 从当前状态角度看,A → B 已经不应该继续显示为 active;
  • 如果用户只希望观察 A 子树,则又不需要展示整个程序历史。

因此,单一调用树逐渐无法同时表达这些语义。

3.2 当前拆分为三种不同语义 ​

我将异步执行信息拆分成:

text
History
Observer
Snapshot

三者分别解决三个不同问题。

三者的关系 ​

目前我对这三者的理解可以概括为:

结构回答的问题数据性质
History过去发生过什么?累计历史事实
Observer历史中我现在想看什么?History 的观察投影
Snapshot当前此刻还成立什么?当前状态重验证

完整架构可以表示为:

text
                   程序真实运行
                        ↓
                 Runtime Breakpoint
                        ↓
                   RuntimeEvent
                        ↓
               History Store / Database
                        ↓
                   History Tree
                        │
                        ├── 完整历史查询
                        │
                        └── + ACTIVE_TRACE_ROOT
                                 ↓
                           Observer Tree
                                 ↓
                          Async Inspector
text
GDB 当前暂停
      ↓
读取当前 Future / Runtime State
      ↓
Current Revalidation
      ↓
Snapshot Tree
      ↓
Async Inspector

前端最终只负责消费结构化的数据。

也就是说,架构从原来更接近:

text
采集信息
 ↓
恢复关系
 ↓
直接展示

逐渐变成:

text
运行事实采集
 ↓
长期事实维护
 ↓
不同语义投影
 ↓
统一数据接口
 ↓
前端展示

调试器开始明确区分:

事实是什么、用户观察什么、当前还成立什么。

4. 补充工作:以异步函数为主体,同步函数辅助恢复执行上下文 ​

随着 whitelist 和 Runtime Trace 范围扩大,还出现了另外一个问题:

程序中并不只有 async 函数。

如果把同步函数和异步函数全部作为同一种节点处理,大量同步函数会进入异步关系恢复过程:

text
同步函数
异步函数
库函数
辅助函数

这样既增加观测开销,也容易让真正的 Future 生命周期关系被大量普通调用信息淹没。

因此目前的处理方式是:

text
Runtime Trace
      ↓
函数类型判断
      ↓
 ┌───────────────┐
 ↓               ↓
Async          Sync
 ↓               ↓
Future/CID      Execution Context
生命周期         调用位置/环境信息
 ↓               ↓
History /      辅助上下文
Snapshot

核心原则是:

异步关系仍然是主体,同步函数不强行进入 Future 生命周期树,而是作为恢复执行上下文的辅助信息。

这部分是在 Runtime Trace 阶段把两种信息分层处理。当前代码和项目总结中也已经明确区分:异步事件进入 Future 生命周期追踪,普通同步事件主要作为执行上下文保留。

5. 本周实验 ​

这周重点开始系统检查:

ARD 恢复出来的异步关系到底什么时候可信,什么时候其实只是证据不足。

目前比较重要的是以下几组实验。

5.1 优化构建下的证据链审计 ​

共检查:

text
32 个固定 binary

其中重点分析:

text
20 个 A4 失败样本

结果:

text
12 个:
R1_NO_ACTIVE_TLS_PARENT

8 个:
R7_NO_CHILD_POLL_EVIDENCE

一个比较重要的发现是:

这些目标关系都没有真正进入 RuntimeRelationValidator。

也就是说,当前失败并不是:

text
正确关系
 ↓
Validator 判断错误
 ↓
被删除

而更接近:

text
编译优化
 ↓
parent / child runtime evidence 缺失
 ↓
关系无法形成
 ↓
没有足够证据进入 Validator

因此现在更倾向于把这类结果判断为:

text
NO_EVIDENCE_INSUFFICIENT

而不是强行恢复一条可能错误的 await 关系。

当前结论

这组实验把问题从:

“优化以后算法为什么错了?”

进一步缩小为:

“优化以后,关系验证需要的运行时证据在哪一个环节消失了?”

5.2 inline frame 是否可以弥补优化造成的信息缺失 ​

针对 optimized binary,又进一步进行了 inline frame 实验。

实验规模:

text
18 个 optimized cell
×
每个重复 10 次

=
180 次 GDB

总共记录约:

text
540 个停止点

实验结果:

项目结果
inline frame 可稳定观察18 / 18
runtime identity 可恢复0 / 18
poll occurrence 可恢复0 / 18
parent-child binding 可恢复0 / 18
validator-ready0 / 18

当前结论

这说明:

逻辑函数帧仍然可见,并不等于 Future 实例级关系也能够恢复。

inline frame 可以帮助理解“代码逻辑上在哪里”,但单独依赖 inline frame 还不足以恢复:

text
这是哪个 Future 实例
        +
这是它第几次 poll
        +
当前 parent 是哪个实例

因此当前结论是:

PARTIALLY_FEASIBLE,而不是完全可替代原有 runtime evidence。

5.3 扩大 Observer / whitelist 范围是否一定有收益 ​

另一组实验检查:

如果观察更多函数,是不是一定能够恢复更多异步关系?

结果并不是完全一致。

Minimal

text
Retention:
83.3% → 83.3%

Peak probes:
120 → 144

Median:
0.418s → 0.662s

结果是:

增加了观测成本,但没有增加有效关系。

Embassy

text
Retention:
13.3% → 26.7%

这里则确实观察到了更多有效节点。

整组正确性和清理检查:

text
80 / 80 通过

当前结论

因此不能简单写成:

“观察范围越大越好。”

更准确的结论是:

扩大观测范围的收益具有 workload dependency。

论文中真正值得研究的是:

text
新增多少观测成本
        ↓
换来了多少新的有效运行证据

而不是简单追求更多 breakpoint 或更多函数。

6. 当前已经确认的边界和失败场景 ​

至少已经发现:

  1. 编译优化可能使 parent identity、child poll evidence、occurrence 等运行时证据缺失;
  2. inline frame 可以保留逻辑位置,但不能直接恢复 Future 实例身份;
  3. 扩大 Observer 范围有时增加有效信息,有时只是增加调试开销;
  4. manual Future 可以恢复 concrete type,但不能假定所有 Future 都具有统一内部 __state;
  5. 多 OS 适配能够证明一定通用性,但仍不能直接推出“对所有 Rust async runtime 通用”。

因此当前的原则是:

证据充分时恢复关系;证据不足时显式保留 unknown / unsupported,而不是为了生成完整的树强行补关系。

7. 论文收束 ​

Contribution 1(模型) 基于可核验证据的 Rust 异步执行表示模型,解决:async 调试中 Future 实例无法持续追踪的问题。 包含:

  • CID
  • poll occurrence
  • activation
  • History
  • Snapshot 用持久的 Future 身份、每次 poll 的执行记录和生效范围表示 Rust 异步调试会话,并区分当前 Snapshot 状态与累积的 History/Observer 状态。

Contribution 2(核心方法) 基于多源运行时证据约束的异步关系恢复机制,解决:如何判断 parent-child await 关系真实存在。 证据:

  • 静态 Future 分析
  • poll event
  • wake
  • thread/task
  • activation 充分则重建,不足展示unknown

Contribution 3(验证和扩展) 面向不同运行环境的异步调试验证与可观测性边界,主要验证:验证方法是否依赖特定环境。 包括:

  • 普通用户程序,比如Minimal
  • Embassy
  • Rel4
  • lilos
  • StarryOS
  • K3
  • QEMU