Skip to content

feat(debug): #1210 内置汇编级调试:反汇编、指令步进、指令断点、寄存器与只读内存 - #1527

Merged
xiaoyumuxi merged 2 commits into
previewfrom
feat/1210-disassembly-debugging
Oct 27, 2026
Merged

xiaoyumuxi merged 2 commits into
previewfrom
feat/1210-disassembly-debugging

Conversation

@xiaoyumuxi

@xiaoyumuxi xiaoyumuxi commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

概述

#1210 在统一调试内核里内置汇编级调试:反汇编、按指令单步、指令断点、寄存器与只读内存。插件仍然只负责启动 lldb-dap / gdb 之类的适配器,这些功能是否可用完全由适配器声明的能力决定,宿主不按适配器 ID 分支。

能力快照规则:supported = 适配器声明 ∧ 已注册扩展 ∧ 已授权。适配器没声明的能力,界面上对应的标签、按钮、gutter 交互都不出现。

功能点

A. 无源码栈帧

  • 没有调试信息的栈帧不再伪造文件名和第 1 行,显示函数名与地址。
  • 暂停后若栈顶帧没有源码,自动打开反汇编标签。

B. 反汇编(debug.inspect kind=disassemble)

  • 新增反汇编视图:地址、机器码、助记符、操作数、符号与源码行注释,当前指令高亮。
  • 单步后如果新 PC 仍在已加载的列表里,只移动高亮并做最小滚动;PC 离开列表才重新加载;剩余行数 ≤ 8 时向后续读。
  • 修复了反汇编文本在窄宽度下折成一团的布局问题。

C. 按指令单步(debug.execute 新增可选 granularity)

  • 仅当适配器声明 supportsSteppingGranularity 时生效。
  • 反汇编标签打开时,步过 / 步入改为按指令前进;按钮提示变为“按指令单步跳过 / 进入”,面板头部显示“按指令单步”。
  • 适配器不支持时,头部提示“该适配器不支持按指令单步,单步仍按源码行前进”,行为保持按行。
  • 关闭反汇编标签后恢复按行单步。

D. 指令断点(debug.setInstructionBreakpoints)

  • 仅当适配器声明 supportsInstructionBreakpoints 时,点击反汇编地址栏设置 / 移除断点。
  • 指令断点只属于当前会话(地址受 ASLR 影响),不写入持久化,新会话不重放。

E. 寄存器与内存

  • 寄存器:作用域 presentationHint: "registers" 显示在独立的“寄存器”标签;宿主不内置 CPU 寄存器表。
  • 内存(debug.inspect kind=readMemory):接受地址或保存着地址的表达式,从目标地址前 64 字节读起,可向前 / 向后分页;读取失败回退为从目标地址读起;读不到的字节显示为缺失而不是 00。
  • 目标字节在十六进制和 ASCII 两侧高亮,并在用户主动读取时滚入可见区。
  • 表头右侧新增显示设置(参考 Visual Studio 内存窗口):进制、每格字节数、每行字节数、字节序、ASCII 列开关。
  • 只读:writeMemory 没有开放(适配器虽声明支持,但扩展未注册,supported = false)。
  • 地址和引用对宿主是不透明字符串,不做地址运算。

连续单步只局部刷新

  • next / stepIn / stepOut / stepBack 期间保留当前检查数据,只读置灰,收到 stopped 后按线程 → 栈 → 作用域 → 变量的顺序原地替换,变量展开状态按名称路径恢复。
  • 线程、调用栈、变量、反汇编、内存与 JSON 视图不再整面板清空重画;单步后变化的内存字节会被标出。
  • 继续、暂停、终止、失败才清空。

变量 JSON 视图

  • 修复顶部多出的空白带。
  • key / value 使用不同颜色高亮(字符串、数字、布尔、null、标点)。

其他

  • i18n:新增词条在 shared/i18n/ 补齐中英文并重新生成,没有手改生成文件,也没有放宽检查脚本。
  • 功能矩阵:新增 debug-disassembly,macOS 已实现(验证待定),Windows 未实现。
  • 设计笔记(optional-debug-extensions、unified-debug-engine-and-adapter-registry)补充了这些能力的设计原因,以及真实 Xcode lldb-dap 的验证结论。
  • shared/contracts/rust-core-api.md、shared/fixtures/debug/projection-v2-examples.json(及 proposals 下的同内容草稿)同步更新。

平台状态

  • macOS:已实现。
  • Windows:尚未实现。共享 Rust 内核已经提供能力快照与 debug.inspect 的 disassemble / readMemory,待 React 界面接入,功能矩阵里标为 missing。

验证

  • ./scripts/verify-rust-core.sh:通过(Rust 测试 1260 + 集成,Swift 桥接、符号链接与 Git 集成)。
  • ./scripts/test-macos.sh --filter 调试相关用例:133 个通过,其中新增 12 个覆盖单步原地刷新、按指令单步、反汇编保留与内存变化标记。
  • node scripts/generate-i18n.mjs --check、node scripts/verify-app-language-localization.mjs、verify-agent-notes、verify-shared-contracts、verify-test-stability、verify-runtime-bundle-immutability、verify-platform-feature-matrix:通过。
  • ./scripts/verify-platform-feature-matrix-change.sh origin/preview HEAD:通过。
  • 真实 Xcode lldb-dap 探测(脚本直接走 DAP):granularity: instruction 让 PC 在同一源码行内前进一条指令(arm64 上 +4 字节),granularity: line 则移到下一行。
  • 真实应用界面(带调试信息的 C 程序):确认反汇编标签、“按指令单步”头部、内存表头偏移、目标字节十六进制 / ASCII 高亮、导航箭头、显示设置图标,以及 JSON 视图配色。

没有在真实应用里亲眼确认的部分

  • 连续单步时的原地刷新、反汇编列表的最小滚动、寄存器标签、显示设置菜单的展开与收起、指令断点的点击切换,这几项我没能在真实应用里自动化驱动出画面,依据是上述单元测试和真实 lldb-dap 探测,建议评审时手动点一遍。
  • 没有调试信息(没带 -g)的程序在进入 main 之前没有可暂停的位置,指令断点需要先用行断点暂停后再在反汇编里设置。

已知事项

  • 仓库里原有一批 Clippy 提示(约 57 条),与本 PR 无关,没有处理。

Review 修复(a89477e12)

  • 单步期间提前冻结旧变量树;在新线程、栈帧、作用域及变量返回前,旧引用不能展开、读取 JSON 或编辑,检查区域保持只读。
  • 在会话同步取消请求前,先使反汇编与内存回调失效;反汇编失败重试检查请求代次,避免切换会话后向旧会话补发请求或覆盖保留数据。
  • 单步期间发生传输失败或会话终止时,清空保留的栈、反汇编与内存,拒绝晚到结果。
  • 内存表头改用请求的 reference,与行偏移基准一致,不再误用返回的页首 address。
  • 新内存输入框和字体测量复用共享 LitheTextField / LitheTheme;同步补充原 Agent Note 与功能矩阵验证步骤。
  • 新增 4 个确定性回归测试:原 PR 代码全部失败,修复后全部通过;本地选定 Swift 测试 152 个通过,Rust 调试域测试 72 个通过。i18n、共享契约、平台边界、bundle 只读、测试稳定性、Agent Notes 与功能矩阵门禁均通过。
  • 已按要求 rebase 到最新 preview c3bd66909,移除中间 merge 提交;PR 仅保留功能提交 604a6c658 与修复提交 a89477e12。已确认 rebase 前后完整文件树逐字节一致,功能与修复内容没有丢失,并以精确 --force-with-lease 更新分支。
  • 验证边界:未重跑完整测试集,未新增真实 GUI、真实调试器端到端或 Windows 实机验收;平台矩阵中的运行时验证状态不变。

Rebase 验证

  • 相对 preview 只有 2 个提交、0 个 merge 提交;preview 的既有提交留在基线,不作为本 PR 新提交。
  • 已重跑功能矩阵变更门禁、功能矩阵校验、bundle 只读、Agent Notes、共享契约及 i18n 检查,全部通过。此次仅整理历史,没有重跑测试套件;前述测试结果为原修复验证记录。

@ghfind-review ghfind-review Bot added the review: medium ghfind author score; see https://ghfind.com label Oct 27, 2026
@xiaoyumuxi
xiaoyumuxi marked this pull request as ready for review October 27, 2026 06:51
@lithe-code-review

lithe-code-review Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Lithe Review

结论: ⛔ 有阻塞
范围: preview ← feat/1210-disassembly-debugging · head: cd678edc

Findings

  1. [P1] 新增反汇编/内存 UI 的用户可见文案绕过统一 i18n 接口
    macos/Sources/Lithe/Views/Debug/GenericDebugDisassemblyView.swift:85

    • 实际影响:反汇编与内存功能在应用语言和系统语言不一致时会显示错误语言;该文件新增的大量标题、按钮、菜单、提示和无障碍标签直接使用 SwiftUI 字符串,例如 Text("Disassembly")、Button("Read")、.action("Read Memory at Address", ...)、.help("Memory display options")、Text("Offsets relative to ...")。这违反仓库要求的统一 shared/i18n/生成结果接入规则。
    • 触发条件:打开反汇编标签或内存标签,或使用指令行/地址上下文菜单、显示设置菜单、分页按钮。
    • 复现步骤:将应用语言设为中文(或系统语言与应用语言设为不同语言),进入一个支持 disassemble/readMemory 的暂停调试会话;上述新增界面仍从 SwiftUI 字面量生成,不能按应用语言统一切换。静态证据还显示新增词条已存在于 shared/i18n,但本文件没有使用相应的 L10n.string/词条入口。
    • 来源:本次引入

Scope Check

  • 关联 Issue 或需求是否完成:Issue [Feature] 类型化 DebugAdapter Registry 与第三方 DAP 接入现有 Debug UI #1210 的反汇编、按指令单步、指令断点、寄存器和只读内存路径在本次 diff 中都有对应 Core、Swift bridge、模型、视图、fixture 和功能矩阵改动;未找到可验证的更细化验收结果,只能按提交内容核对实现范围。
  • 已完成范围:检查了 Rust Core 的能力注册、execute 粒度门控、setInstructionBreakpoints、debug.inspect 的 disassemble/readMemory 参数校验与归一化、DAP 结果解析、Swift bridge/session manager、反汇编/内存模型、Debug UI 接入、共享契约/fixture、i18n 词条和功能矩阵记录。
  • 未完成范围:Windows 仍标记为未实现;PR 描述称真实应用中未亲眼确认连续单步原地刷新、最小滚动、寄存器标签、显示设置菜单和指令断点点击切换,因此这些交互仍缺少运行时证据。由于本次只读审查没有启动应用或测试,无法替代这些平台/界面验证。
  • 是否复用了已有上游能力,或对自研边界给出充分证据:Core 主要转发 DAP 的成熟请求并做稳定契约归一化;但 PR 未提供足够的上游能力/版本与长期所有权证据来证明新增 UI/模型边界,属于信息缺口而非额外阻塞 Finding。
  • 每个 Finding 是否由本次变更引入或加剧:是,Finding 1 全部位于新增的 GenericDebugDisassemblyView.swift 文案路径。
  • 是否属于本次变更职责范围:是;新增用户可见 UI 必须在同一改动中接入统一 i18n。

Suggestions

  1. 将 GenericDebugDisassemblyView.swift 中所有新增用户可见标题、按钮、菜单项、帮助文本、占位符和无障碍标签改为共享 i18n 词条:视图字面量使用已新增词条对应的 LocalizedStringKey/统一 SwiftUI 入口,视图外字符串使用 L10n.string;带参数的提示(例如不可读字节数、相对地址、变化字节数)使用既有生成参数形式。随后重新生成并检查 Localizable.strings,并提供 node scripts/verify-app-language-localization.mjs 与 node scripts/generate-i18n.mjs --check 的结果。
  2. 补充 PR 描述或评论中的受影响界面截图,并提供前后对比或至少展示反汇编、寄存器、内存和显示设置菜单;当前上下文只说明曾手动确认部分画面,未附截图,视觉效果尚未验证。
  3. 在可运行环境补齐未亲眼验证的连续单步原地刷新、反汇编最小滚动、寄存器标签、显示设置菜单展开/收起和指令断点点击切换验证;本次审查没有运行任何测试或应用。

Summary

Rust Core 的能力快照、请求边界、引用长度/读取大小限制、过期操作保护和 Swift bridge 的整体方向与 DAP 适配边界一致,新增测试和共享契约覆盖面也较大。当前不能通过审查的明确原因是新增 Debug UI 大量直接硬编码用户可见字符串,尽管同一 PR 已添加对应共享 i18n 词条;这会直接造成语言选择不一致,按规则属于 P1。Windows 功能和若干高频交互仍缺少真实运行证据,但属于非阻塞验证缺口。

Verification

  • 实际检查的文件、提交和调用链:以 ce7098c09d3faba9783600dc33985c49ae42868f...cd678edcc9465205973213cbae5c00e1d0c2921d 为范围,检查了 rust/lithe-core/src/debug/{engine.rs,types.rs,capabilities.rs}、rust/lithe-core/src/runtime/dispatcher.rs、macos/Sources/LitheCoreContracts/Debug/*、macos/Sources/LitheDebugModule/{Application,Runtime}/*、macos/Sources/Lithe/Views/Debug/GenericDebugDisassemblyView.swift、GenericDebugView.swift、共享契约/fixture/i18n/功能矩阵和相关 Agent Notes;沿着 Core dispatcher → Swift bridge/session → feature model → disassembly/memory view 追踪了调用链。
  • 已提供的测试或 CI 结果:仅记录 PR 上下文中作者声称的结果(Rust Core、macOS 调试相关用例、i18n、契约、稳定性、运行时 bundle 不可变性和功能矩阵检查);本审查未重新运行这些检查。
  • 本次未运行的测试:所有测试、构建、应用启动、真实 DAP/Xcode 探测和 i18n 验证脚本均未运行,遵守远程审查只读约束。
  • 仍存在的非阻塞风险或平台验证缺口:Windows 前端尚未实现;PR 自述的连续单步原地刷新、最小滚动、寄存器标签、显示设置菜单和指令断点点击切换缺少真实应用证据;未提供界面截图。

@xiaoyumuxi

Copy link
Copy Markdown
Collaborator Author
image

xiaoyumuxi added a commit that referenced this pull request Oct 27, 2026
Integrate the disassembly debugging branch with preview at cdeec19. Preserve both the Java transport notes and optional native-debug notes when resolving their documentation conflict.
内核按适配器能力开放汇编级调试,插件只负责启动 lldb-dap/gdb 等适配器;能力快照 supported = 适配器声明 ∧ 已注册扩展 ∧ 已授权。

- 无源码栈帧:栈帧不伪造文件和第 1 行,显示函数名与地址,暂停后自动打开反汇编

- 反汇编:debug.inspect disassemble 与反汇编视图,高亮当前指令,保持最小滚动,剩余不足时向后续读

- 指令步进:debug.execute 增加 granularity,仅适配器声明 supportsSteppingGranularity 时生效;反汇编打开时步过/步入按指令前进,面板头部与按钮提示同步变化,不支持时提示仍按源码行前进

- 指令断点:debug.setInstructionBreakpoints,点击地址栏设置或移除;只属于当前会话,不持久化、不重放

- 寄存器:作用域 presentationHint registers 显示为寄存器标签;宿主不内置 CPU 寄存器表

- 内存:debug.inspect readMemory,接受地址或保存着地址的表达式,从目标前 64 字节读起并分页;目标字节在十六进制和 ASCII 两侧高亮并滚入可见区;右侧显示设置可切换进制、每格字节数、每行字节数、字节序与 ASCII 列;读不到的字节显示为缺失;只读,不开放 writeMemory

- 单步局部刷新:next/stepIn/stepOut/stepBack 保留现有检查数据并原地替换,线程、调用栈、变量、反汇编、内存与 JSON 视图不再整面板清空,变化的内存字节被标出;继续、暂停、结束才清空

- 变量 JSON 视图:修复顶部空白带,key/value 分色高亮

- i18n:新增词条走 shared/i18n 并生成;功能矩阵新增 debug-disassembly(Windows 待实现);设计笔记补充真实 lldb-dap 验证结论
…tion

Freeze the old variable tree before the next stop reloads scopes and keep inspection controls read-only until replacement. Retire disassembly and memory callbacks before synchronous cancellation, and reject stale disassembly retries after session changes. Clear retained inspection when transport fails or the session terminates.

Label memory offsets relative to the requested reference, use shared text-input and font owners, and update the owning decision note and platform verification steps.

Add four deterministic regressions reproduced against the original PR. Validation: 152 selected Swift tests and 72 Rust debug tests passed; i18n, shared contracts, platform boundaries, test stability, Agent Notes, matrix gates and runtime bundle immutability passed. Real GUI and Windows runtime validation remain pending.
@xiaoyumuxi
xiaoyumuxi force-pushed the feat/1210-disassembly-debugging branch from ee56e96 to a89477e Compare October 27, 2026 12:28
@xiaoyumuxi
xiaoyumuxi merged commit edb8c36 into preview Oct 27, 2026
17 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: medium ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant