Skip to content

feat(starry-kernel): improve GDB usability#1167

Merged
ZR233 merged 1 commit into
rcore-os:devfrom
Promin3:feat/starryos-gdb-usability
Jun 8, 2026
Merged

feat(starry-kernel): improve GDB usability#1167
ZR233 merged 1 commit into
rcore-os:devfrom
Promin3:feat/starryos-gdb-usability

Conversation

@Promin3

@Promin3 Promin3 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

背景

PR931 已经为 StarryOS 引入了 riscv64 GDB/ptrace 的初步支持,但早期实现偏向 process-centric 语义:部分 ptrace stop、wait、clone event 路径仍默认“一个进程一个 stop 状态”。这会影响 GDB/gdbserver 对 LWP/TID、多线程断点、__WALL wait、/proc/<pid>/task 等路径的使用。

本 PR 将 GDB 支持收口到当前阶段的 usable subset:以 explicit-TID all-stop 为核心,优先保证 native GDB、guest 内 gdbserver、host-to-guest remote GDB 的基础可演示和可回归能力。

修改内容

  • 重构 ptrace stop 状态:

    • stop record 按 TID 保存,而不是按进程保存单一 stop。
    • resume signal、syscall trace、single-step、FP register snapshot、pending event 均按 TID 绑定。
    • PTRACE_GETREGSET / PTRACE_SETREGSET / GETSIGINFO / GETEVENTMSG 等请求会绑定到当前 stop TID。
  • 调整 wait / waitid 语义:

    • 支持 traced thread stop 通过 waitpid(..., __WALL) 被消费。
    • explicit TID wait 时返回对应 TID。
    • waitid() 的 ptrace stop si_pidwaitpid() 的 report pid 逻辑保持一致,不再无条件报告 thread group pid。
  • 调整 clone/fork/vfork ptrace event:

    • clone/fork/vfork event 记录 parent tid 和 new tid。
    • 普通 clone/fork 事件由 parent 返回用户态后绑定到具体 parent tid stop。
    • 新线程/新子进程 stop 绑定到 new tid。
    • vfork 保留必要的额外唤醒路径,避免 parent 在内核等待 vfork completion 时无法消费 pending event。
  • 补充 procfs / GDB 可用性支持:

    • 增强 /proc/<pid>/status/proc/<pid>/task/proc/<pid>/auxv、maps/exe 等 GDB 常用信息路径。
    • 支撑 info threadsinfo proc mappingsinfo auxvinfo files 等基础 GDB 查询。
  • 增加 GDB smoke app:

    • apps/starry/gdb-smoke 提供 native GDB、gdbserver、host-to-guest remote GDB、pthread、manual demo、opt-in stress 入口。
    • apps/starry/gdb-smoke 已在 apps/.ignore 中,不进入默认 Starry app smoke CI。
    • manual / host-to-guest / stress 配置仅作为显式 opt-in 验证和人工演示入口。
  • 增加和调整回归测试:

    • test-ptrace-gdb
    • test-ptrace-traceme-stop
    • test-ptrace-wait-wall
    • test-ptrace-thread-traceclone-wall
    • test-proc-status-tracerpid
    • test-proc-task-status-tid

设计说明

本 PR 以当前 explicit-TID ptrace/wait 语义为准,不继续保留 PR931 中与当前目标不一致的 process-pid 多线程调试假设。

旧的 process-pid 多线程 breakpoint 压力路径不作为默认 normal CI blocker;GDB 专属压力验证放在 apps/starry/gdb-smoke 的 opt-in stress 配置中,避免普通 CI 被人工演示或重型调试路径拖慢。

本地验证

已在 Docker 环境中验证:

cargo fmt --all -- --check
cargo xtask sync-lint --since origin/dev
cargo xtask clippy --package starry-kernel

@Promin3
Promin3 force-pushed the feat/starryos-gdb-usability branch from b35b422 to 9269e52 Compare June 6, 2026 15:22
@mai-team-app mai-team-app Bot mentioned this pull request Jun 6, 2026

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #1167 Review 总结

变更概述

本 PR 将 StarryOS 的 ptrace 支持从 process-centric 单一 stop 模型重构为 explicit-TID per-thread stop 模型,以支撑 GDB/gdbserver 的多线程调试需求。修改范围包括:

  • ptrace 状态重构task/mod.rs):所有 ptrace 状态字段(stop record、resume signo、syscall trace、single-step、FP snapshot、saved instruction、pending event)从单一值改为 BTreeMap<u32, ...> 按 TID 键控。新增 PtraceStopRecordPtracePendingEvent 结构体。
  • ptrace syscall 层ptrace.rs):所有 ptrace 请求(CONT/SINGLESTEP/SYSCALL/DETACH/GETREGSET/SETREGSET/GETSIGINFO/SETSIGINFO/GETEVENTMSG)改为使用 ptrace_stopped_tracee_with_tid() 获取精确 stop TID。修复 PTRACE_SETOPTIONS 参数从 addr 改为 data(符合 Linux 语义)。clone/exec/exit/vfork-done 通知改为使用 set_ptrace_pending_event(tid, ...) 模式。
  • wait/waitidwait.rs):新增 matches_process_or_thread() 支持 TID 直接等待;新增 ptrace_report_pid() 在 explicit TID wait 时返回请求的 TID;新增 ptrace_unreported_stop / ptrace_unreported_stop_for 从 BTreeMap 中选择合适的 stop。
  • clone/fork/vforkclone.rs):clone 事件记录 parent_tidchild_tid,pending event 绑定到 parent tid;新线程 stop 绑定到 tid;vfork_done 不再单独发 SIGTRAP,改为 pending event 模式。
  • 信号路径signal.rs):新增 wait_existing_ptrace_stop_current 处理已有 stop 的重新进入;ptrace_stop_current_impl 新增 claim_ptrace_stop(tid) 循环确保同一 TID 不会重入 stop。
  • 用户态循环user.rs):优先检查线程级 stop,再检查进程级 stop;clone 后的 pending event 通过返回用户态前的检查触发 stop。
  • procfs 增强proc.rs):/proc/<pid>/status 新增 TracerPidPPidStateName 字段;task status 重构为 TaskStatusBase / TaskStatusFields 结构体。
  • GDB smoke appapps/starry/gdb-smoke):6 种 QEMU 配置(batch native、manual native、threads、gdbserver、gdbserver-debug、gdbserver-host、stress)。
  • 新增/修改测试test-ptrace-gdbtest-ptrace-traceme-stoptest-ptrace-wait-walltest-ptrace-thread-traceclone-walltest-proc-status-tracerpidtest-proc-task-status-tid

实现逻辑评估

  1. Per-TID BTreeMap 选型正确:OS 内核环境中 BTreeMap 比 HashMap 更合适,不依赖全局 allocator 随机化。每个 ptrace 操作都通过 _for(tid) 变体精确操作目标线程,保持了一致的 API 模式。
  2. Pending event 模式合理:clone/vfork-done/exec 事件先存入 ptrace_pending_event,在目标 TID 的下一次 set_ptrace_stop 时自动消费并合并到 PtraceStopRecord。这避免了旧实现中 process-pid 级别的 event/event_msg 无法区分多个并发事件的问题。
  3. Wait 语义正确WaitTarget::matches_process_or_thread() 正确处理了 waitpid(tid, __WALL) 查找线程的场景。ptrace_report_pid() 在 explicit TID wait 时返回请求的 TID 而非 thread group pid,符合 Linux 语义。
  4. PTRACE_SETOPTIONS 修复正确:Linux man page 明确规定 ptrace(PTRACE_SETOPTIONS, pid, 0, options),options 在 data 参数中。
  5. Clone 事件行为调整合理:旧实现在所有 clone 后给 parent 发 SIGTRAP;新实现通过 user.rs 中的 has_ptrace_pending_event_for(tid) 检查在返回用户态时触发 stop,更干净。
  6. Signal bypass per-TID 化ptrace_resume_signal_bypass 从进程级 Atomic 改为 per-TID BTreeMap,避免多线程调试时信号绕过注入错误目标线程。

本地验证结果

cargo fmt --all -- --check          # PASS (无输出)
cargo xtask clippy --package starry-kernel  # PASS (13/13 checks, 0 failed)

无 Cargo.toml / Cargo.lock 变更,无 [patch.crates-io]

CI 状态

  • 成功:Detect changed paths、Run sync-lint / run_host、Check formatting / run_host、Test axvisor riscv64 qemu / run_host、Test axvisor self-hosted board phytiumpi-linux / run_host、Test axvisor loongarch64 qemu / run_container、Test axvisor self-hosted x86_64 UEFI / run_host、Test axvisor self-hosted x86_64 / run_host、Test axvisor self-hosted board orangepi-5-plus-linux / run_host、Test starry self-hosted board licheerv-nano-sg2002 / run_host。
  • 跳过(预期行为):run_container 变体(对应 run_host 已运行)、Publish jobs、部分 axvisor/arch 矩阵 job(路径过滤未触发)。
  • 进行中:Test starry riscv64 qemu / run_container、Test arceos riscv64/aarch64/loongarch64 qemu、Test starry aarch64/loongarch64/x86_64 qemu。这是 CI 矩阵正常执行,尚无失败。
  • 注意:mergeable_state=unstable 仅因 CI 仍在运行,非冲突。

重复与重叠分析

  • PR #931(已合并):初始 GDB ptrace 支持。本 PR 在其基础上做 per-TID 重构,是自然的演进,不重复。
  • PR #1168(open):TUI 修复(FIOCLEX ioctl、/proc status ctxt_switches、NotATty 降噪)。虽修改 proc.rs 但只增加 ctxt_switches stub 字段,与本 PR 增加的 TracerPid/PPid/State 字段互补,无冲突风险。
  • PR #1076(open):StarryOS x86_64 自编译。完全不同的修改区域。
  • 无其他 ptrace/GDB 相关 open PR。

结论

实现逻辑正确,重构一致,测试覆盖充分(6 个 test-suit case + GDB smoke app),本地验证通过,CI 进展正常无失败。推荐 APPROVE。

Powered by mimo-v2.5-pro

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我完整看了 #1167 的 ptrace/wait/procfs 主路径、相关测试和当前 CI。整体 per-TID stop 重构方向是对的,新增 waitpid(..., __WALL)、TRACECLONE、proc status 等回归也很有价值;当前 head 上远端 formatting、sync-lint、clippy 和 Starry 四架构 QEMU 都是通过状态,我本地也跑了 cargo fmt --check,通过。

阻塞点集中在 waitid(P_PID, <non-leader tid>, ...):当前代码会把返回给用户的 child_pid 设成 TID,但后续用这个 TID 去 get_process_data(),而进程表只按 thread-group leader pid 查找,导致非 WNOWAIT 的 waitid 不会把该 TID 的 ptrace stop 标记为 reported。请修正并补一个非 leader TID 的 waitid 回归。

Comment thread os/StarryOS/kernel/src/syscall/task/wait.rs Outdated

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮复审基于当前 head 79fc43df48e6532903a36c4a4f2615e62b2e61c8

之前阻塞的 waitid(P_PID, <non-leader tid>, ...) 漏标记问题已经修正:waitid() 现在沿用前面选中的 (data, stop_tid),非 WNOWAIT 时直接 mark_ptrace_stop_reported_for(stop_tid),不再用对外报告的 TID 重新查 get_process_data()。新增的 test-ptrace-thread-traceclone-wall 会对 clone 出来的 non-leader TID 做 exact waitid(P_PID, new_tid, WSTOPPED | __WALL),随后立刻用 WNOHANG 重复 wait,能覆盖旧实现重复报告同一个 stop 的问题;同一用例还验证了按 TID 的 GETSIGINFOGETREGSETSETOPTIONSCONT 路径。

实现方面,ptrace stop / pending event / syscall trace / single-step / FP snapshot / resume signal 均改为按 TID 记录,ptrace_stopped_tracee_with_tid() 支持后续 ptrace 操作以进程 leader 或 stopped TID 定位同一 tracee,waitpid/waitid 的 report pid 与 explicit TID wait 语义也保持一致。procfs 侧新增 /proc/<pid>/task/<tid>TracerPid、真实 Pid/Tgid、auxv/maps/exe 等 GDB 常用入口,和 native GDB、gdbserver 的使用路径相匹配。需要说明的是,当前实现仍以 PR 描述的 explicit-TID all-stop usable subset 为边界;例如初始 PTRACE_ATTACH/SEIZE 到非 leader TID 仍不是这次覆盖的入口,但本 PR 新增的 GDB/gdbserver/app 流程不依赖该路径。

验证情况:

  • 本地 git diff --check origin/dev...HEAD 通过。
  • 本地 cargo fmt --all -- --check 通过。
  • 本地对本 PR 修改/新增的 10 个 C 文件执行 gcc -Wall -Wextra -Werror -fsyntax-only ... 全部通过。
  • 当前 head 的 GitHub Actions run 27115813614 成功,覆盖 formatting、sync-lint、clippy、std,以及 Starry x86_64/riscv64/aarch64/loongarch64 QEMU;互斥 host/container 和发布类 skipped job 属于预期矩阵路径。
  • apps/starry/gdb-smokeapps/.ignore 中,不进入默认 app smoke CI,我在当前 head 额外跑了实际 app QEMU 流程:cargo xtask starry app qemu -t gdb-smoke --arch riscv64 通过并匹配 GDB_NATIVE_SMOKE_DONE,覆盖 guest native GDB breakpoint、backtrace、info proc mappings/files/auxv/proc/<pid>/status、register/memory 读取和 stepicargo xtask starry app qemu -t gdb-smoke --arch riscv64 --qemu-config qemu-riscv64-gdbserver-debug.toml 通过并匹配 GDBSERVER_SMOKE_DONE,覆盖 guest gdbserver、remote GDB、pthread thread listing、non-leader thread breakpoint、pending trap 消费和正常退出。

重复/重叠检查:origin/dev 中没有等价的 per-TID ptrace stop/wait/procfs GDB usable subset;开放 PR 中 #1052 只与 test-ptrace-gdb 的 attach 同步相邻,#1062/#1017 与 ptrace/procfs 有相邻改动但意图不同,#1168 只在 procfs 字段上互补,未发现替代或阻塞本 PR 的重复实现。当前 base 更新后用 merge-tree 检查没有冲突;GitHub 的 BLOCKED 状态来自仍待更新的 review 聚合,不是 dirty merge。

旧 review thread 已解析并确认 isResolved=true。结论:当前实现、回归和 app 运行证据满足本 PR 目标,可以合并。

@ZR233
ZR233 merged commit dd16995 into rcore-os:dev Jun 8, 2026
49 checks passed
silicalet added a commit to silicalet/tgoskits that referenced this pull request Jun 8, 2026
Resolve merge conflict in lock.rs:
- Merge upstream fcntl deadlock detection (PosixLockWaitGuard, EDEADLK)
  with our wchan-aware wait (WaitChannel::FileLockWait)
- Keep both LinuxError import (upstream) and WaitChannel import (ours)
- 6 other overlapping files auto-resolved cleanly

Upstream commits merged:
- 6ebaa40 feat(starry-kernel): detect fcntl lock deadlocks (rcore-os#1055)
- 2f8e28d feat(starry-proc): add /proc/sys and /proc/filesystems (rcore-os#1121)
- dd16995 feat(starry-kernel): improve GDB ptrace usability (rcore-os#1167)
- 690274f feat(starry-kernel): support futex WAKE_OP (rcore-os#1052)
- 6e587f4 test(starry): add git remote stress probes (rcore-os#1169)
54dK3n pushed a commit to 54dK3n/tgoskits that referenced this pull request Jun 8, 2026
- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审总结

变更概述

本 PR 将 StarryOS 的 ptrace 子系统从 process-centric 单一 stop 模型重构为 explicit-TID per-thread stop 模型,以支持 GDB/gdbserver 的多线程调试。修改范围:

  • ptrace 状态重构task/mod.rs,+513/-旧):所有 ptrace 状态字段(stop record、resume signo、syscall trace、single-step、FP snapshot、saved instruction、pending event)从单一值改为 BTreeMap<u32, ...> 按 TID 键控。新增 PtraceStopRecordPtracePendingEvent 结构体。
  • ptrace 请求层ptrace.rs,+120/-旧):CONT/SINGLESTEP/SYSCALL/DETACH/GETREGSET/SETREGSET/GETSIGINFO/SETSIGINFO/GETEVENTMSG 改用 ptrace_stopped_tracee_with_tid() 精确定位 stop TID。修复 PTRACE_SETOPTIONS 参数从 addr 改为 data(符合 Linux 语义)。
  • wait/waitidwait.rs,+77/-旧):新增 matches_process_or_thread() 支持 TID 直接等待;ptrace_report_pid() 在 explicit TID wait 时返回请求的 TID。非 WNOWAIT 时直接 mark_ptrace_stop_reported_for(stop_tid),不再通过 get_process_data() 查找。
  • clone/fork/vforkclone.rs,+28/-旧):clone 事件记录 parent_tidchild_tid,pending event 绑定到 parent tid;新线程 stop 绑定到 tid;vfork_done 改为 pending event 模式。
  • 信号路径signal.rs,+88/-旧):新增 wait_existing_ptrace_stop_current 处理已有 stop 重新进入;ptrace_stop_current_impl 新增 claim_ptrace_stop(tid) 循环防重入。
  • procfs 增强proc.rs,+310/-旧):/proc/<pid>/status 新增 TracerPidPPidStateName 字段;task status 重构为 TaskStatusBase/TaskStatusFields。增加 auxv/maps/exe 等 GDB 常用路径。
  • GDB smoke appapps/starry/gdb-smoke):6 种 QEMU 配置(native batch、manual、threads、gdbserver、gdbserver-debug/host、stress)。
  • 测试覆盖test-ptrace-gdbtest-ptrace-traceme-stoptest-ptrace-wait-walltest-ptrace-thread-traceclone-walltest-proc-status-tracerpidtest-proc-task-status-tid

实现逻辑评估

  1. Per-TID BTreeMap 选型正确:OS 内核环境中 BTreeMap 不依赖全局 allocator 随机化,适合 no_std 场景。每个 ptrace 操作都通过 _for(tid) 变体精确操作目标线程,保持 API 一致性。
  2. Pending event 模式合理:clone/vfork-done/exec 事件先存入 ptrace_pending_event,在目标 TID 的下一次 set_ptrace_stop 时自动消费并合并到 PtraceStopRecord。避免旧实现中 process-pid 级别 event/event_msg 无法区分多个并发事件的问题。
  3. Wait 语义正确matches_process_or_thread() 正确处理 waitpid(tid, __WALL)ptrace_report_pid() 在 explicit TID wait 时返回请求的 TID,符合 Linux 语义。
  4. PTRACE_SETOPTIONS 修复:Linux man page 规定 ptrace(PTRACE_SETOPTIONS, pid, 0, options),options 在 data 参数中。修复正确。
  5. Waitid 非 leader TID 修复waitid(P_PID, <non-leader tid>, ..., WSTOPPED) 之前存在漏标记问题(用 report pid 查 get_process_data() 无法命中非 leader TID)。已修正为直接使用 data.mark_ptrace_stop_reported_for(stop_tid)。新增的 test-ptrace-thread-traceclone-wallWNOHANG 重复 wait 覆盖了该场景。
  6. Signal bypass per-TID 化ptrace_resume_signal_bypass 从进程级 Atomic 改为 per-TID BTreeMap,避免多线程调试时信号绕过注入错误目标线程。

本地验证结果

cargo fmt --all -- --check              # PASS(无输出)
cargo xtask clippy --package starry-kernel  # PASS(13/13 checks, 0 failed)
git diff --check origin/dev...HEAD      # PASS(无输出)

Cargo.toml/Cargo.lock 变更,无 [patch.crates-io]

CI 状态

GitHub Actions run 27115813614(head SHA 79fc43df48):

  • 成功(20+ job):Detect changed paths、Run sync-lint/run_host、Check formatting/run_host、Run clippy/run_host、Test with std/run_host、Test starry x86_64/aarch64/loongarch64 QEMU(run_container/run_host)、Test axvisor riscv64/aarch64 QEMU/run_host、Test axvisor x86_64 svm hosted/run_host、Test axvisor self-hosted x86_64 UEFI/run_host、Test axvisor self-hosted x86_64/run_host、Test axvisor self-hosted board phytiumpi-linux/orangepi-5-plus-linux/roc-rk3568-pc-linux/run_host、Test arceos riscv64/aarch64/loongarch64 QEMU/run_host、Test starry self-hosted board licheerv-nano-sg2002/orangepi-5-plus/run_host。
  • 跳过(预期行为):run_container 变体(对应 run_host 已运行)、Publish jobs、部分 arch matrix job(路径过滤未触发)。跳过数约 15 个,均属互斥矩阵路径。
  • 失败:0

重复与重叠分析

  • PR #931(已合并):初始 GDB ptrace 支持。本 PR 在其基础上做 per-TID 重构,是自然的演进,不重复。
  • PR #1168(open):TUI 修复(FIOCLEX ioctl、/proc status ctxt_switches)。修改 proc.rs 但只增加 ctxt_switches stub 字段,与本 PR 增加的 TracerPid/PPid/State 字段互补,无冲突风险。
  • PR #1173(open):RSS accounting。完全不同的修改区域。
  • PR #1174(open):ArceOS test suite 整合。完全不同的修改区域。
  • origin/dev 中没有等价的 per-TID ptrace stop/wait/procfs GDB usable subset。

审查历史

  1. ZR233 首轮发现 waitid(P_PID, <non-leader tid>, ...) 漏标记问题并 REQUEST_CHANGES。
  2. Promin3 修复后提交新 head 79fc43df48,补充 test-ptrace-thread-traceclone-wall 覆盖。
  3. ZR233 复审确认修复正确,APPROVE。
  4. 已合并(merge commit dd169952d)。

结论

实现逻辑正确,per-TID 重构一致且符合 Linux ptrace 语义。测试覆盖充分(6 个 test-suit case + GDB smoke app)。无阻塞问题,无 crates.io patch,无重复/冲突风险。推荐 APPROVE。

Powered by mimo-v2.5-pro

@github-actions github-actions Bot mentioned this pull request Jun 9, 2026
aptacc2421 pushed a commit to aptacc2421/tgoskits that referenced this pull request Jun 14, 2026
54dK3n pushed a commit to 54dK3n/tgoskits that referenced this pull request Jun 17, 2026
- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix
ZR233 pushed a commit that referenced this pull request Jun 18, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR #1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

---------

Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
SongShiQ pushed a commit to SongShiQ/tgoskits that referenced this pull request Jun 19, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR rcore-os#1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

---------

Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
ZR233 added a commit that referenced this pull request Jun 21, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR #1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

* chore(repo): remove unused workspace crates (#1306)

* feat(axbuild): internalize Starry kallsyms flow (#1309)

* fix(ci): bump smoke-vmx QEMU timeout 180→600s for self-hosted KVM runner (#1315)

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>

* fix(starry): correct x86_64 u_debugreg offset in struct user

x86_64 PTRACE_PEEKUSER/POKEUSER on the debug-register area used
X86_64_USER_DEBUGREG_OFFSET = 912, but u_debugreg[] sits at offset 848 in
the x86_64 `struct user` (regs 216 + u_fpvalid/pad 8 + i387 512 + tsize/
dsize/ssize 24 + start_code/start_stack 16 + signal 8 + reserved/pad 8 +
u_ar0 8 + u_fpstate 8 + magic 8 + comm 32 = 848).

gdbserver probes the hardware debug registers (DR0–DR7) via PEEKUSER at
this offset during startup; with the wrong offset it read a bogus location
and stalled before printing "Listening on port 1234", so the x86_64
gdbserver smoke hung. The native single-process GDB smoke does not touch
debug registers, which is why only the gdbserver path was affected.

Fix the offset to 848. Verified end-to-end in the container: the x86_64
gdbserver smoke now reaches GDBSERVER_SMOKE_DONE.

* feat(gdb-smoke): port GDB and gdbserver smoke to x86_64

参照现有 riscv64/aarch64/loongarch64 实现,为 gdb-smoke 增加 x86_64 的
原生 GDB 冒烟与单进程 gdbserver 冒烟移植:

- 新增 build-x86_64-unknown-none.toml 与默认 qemu-x86_64.toml(native
  批量冒烟,成功标志 GDB_NATIVE_SMOKE_DONE);
- 补齐 gdbserver 全套:qemu-x86_64-gdbserver.toml(默认 gdbserver 冒烟,
  GDBSERVER_SMOKE_DONE)、gdbserver-host.toml、gdbserver-manual.toml,以及
  host-remote-x86_64.gdb / host-manual-x86_64.gdb(set architecture
  i386:x86-64);
- prebuild.sh 的 find_qemu_runner 增加 x86_64 分支(qemu-x86_64 +
  x86_64-linux-musl);
- README 补充 x86_64 native 与 gdbserver 用法。

gdbserver 路径依赖同分支的 x86_64 u_debugreg 偏移修复才能跑通。已在容器内
验证:native 冒烟 GDB_NATIVE_SMOKE_DONE、gdbserver 冒烟 GDBSERVER_SMOKE_DONE
均通过(断点/backtrace/continue/远程连接/正常退出全部正确)。

---------

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: 周睿 <34859362+ZR233@users.noreply.github.com>
Co-authored-by: 禾可 <chengkelfan@qq.com>
Antareske pushed a commit to Antareske/tgoskits that referenced this pull request Jun 27, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR rcore-os#1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

---------

Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Antareske pushed a commit to Antareske/tgoskits that referenced this pull request Jun 27, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR rcore-os#1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

* chore(repo): remove unused workspace crates (rcore-os#1306)

* feat(axbuild): internalize Starry kallsyms flow (rcore-os#1309)

* fix(ci): bump smoke-vmx QEMU timeout 180→600s for self-hosted KVM runner (rcore-os#1315)

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>

* fix(starry): correct x86_64 u_debugreg offset in struct user

x86_64 PTRACE_PEEKUSER/POKEUSER on the debug-register area used
X86_64_USER_DEBUGREG_OFFSET = 912, but u_debugreg[] sits at offset 848 in
the x86_64 `struct user` (regs 216 + u_fpvalid/pad 8 + i387 512 + tsize/
dsize/ssize 24 + start_code/start_stack 16 + signal 8 + reserved/pad 8 +
u_ar0 8 + u_fpstate 8 + magic 8 + comm 32 = 848).

gdbserver probes the hardware debug registers (DR0–DR7) via PEEKUSER at
this offset during startup; with the wrong offset it read a bogus location
and stalled before printing "Listening on port 1234", so the x86_64
gdbserver smoke hung. The native single-process GDB smoke does not touch
debug registers, which is why only the gdbserver path was affected.

Fix the offset to 848. Verified end-to-end in the container: the x86_64
gdbserver smoke now reaches GDBSERVER_SMOKE_DONE.

* feat(gdb-smoke): port GDB and gdbserver smoke to x86_64

参照现有 riscv64/aarch64/loongarch64 实现,为 gdb-smoke 增加 x86_64 的
原生 GDB 冒烟与单进程 gdbserver 冒烟移植:

- 新增 build-x86_64-unknown-none.toml 与默认 qemu-x86_64.toml(native
  批量冒烟,成功标志 GDB_NATIVE_SMOKE_DONE);
- 补齐 gdbserver 全套:qemu-x86_64-gdbserver.toml(默认 gdbserver 冒烟,
  GDBSERVER_SMOKE_DONE)、gdbserver-host.toml、gdbserver-manual.toml,以及
  host-remote-x86_64.gdb / host-manual-x86_64.gdb(set architecture
  i386:x86-64);
- prebuild.sh 的 find_qemu_runner 增加 x86_64 分支(qemu-x86_64 +
  x86_64-linux-musl);
- README 补充 x86_64 native 与 gdbserver 用法。

gdbserver 路径依赖同分支的 x86_64 u_debugreg 偏移修复才能跑通。已在容器内
验证:native 冒烟 GDB_NATIVE_SMOKE_DONE、gdbserver 冒烟 GDBSERVER_SMOKE_DONE
均通过(断点/backtrace/continue/远程连接/正常退出全部正确)。

---------

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: 周睿 <34859362+ZR233@users.noreply.github.com>
Co-authored-by: 禾可 <chengkelfan@qq.com>
Antareske pushed a commit to Antareske/tgoskits that referenced this pull request Jun 27, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR rcore-os#1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

---------

Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Antareske pushed a commit to Antareske/tgoskits that referenced this pull request Jun 27, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR rcore-os#1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

* chore(repo): remove unused workspace crates (rcore-os#1306)

* feat(axbuild): internalize Starry kallsyms flow (rcore-os#1309)

* fix(ci): bump smoke-vmx QEMU timeout 180→600s for self-hosted KVM runner (rcore-os#1315)

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>

* fix(starry): correct x86_64 u_debugreg offset in struct user

x86_64 PTRACE_PEEKUSER/POKEUSER on the debug-register area used
X86_64_USER_DEBUGREG_OFFSET = 912, but u_debugreg[] sits at offset 848 in
the x86_64 `struct user` (regs 216 + u_fpvalid/pad 8 + i387 512 + tsize/
dsize/ssize 24 + start_code/start_stack 16 + signal 8 + reserved/pad 8 +
u_ar0 8 + u_fpstate 8 + magic 8 + comm 32 = 848).

gdbserver probes the hardware debug registers (DR0–DR7) via PEEKUSER at
this offset during startup; with the wrong offset it read a bogus location
and stalled before printing "Listening on port 1234", so the x86_64
gdbserver smoke hung. The native single-process GDB smoke does not touch
debug registers, which is why only the gdbserver path was affected.

Fix the offset to 848. Verified end-to-end in the container: the x86_64
gdbserver smoke now reaches GDBSERVER_SMOKE_DONE.

* feat(gdb-smoke): port GDB and gdbserver smoke to x86_64

参照现有 riscv64/aarch64/loongarch64 实现,为 gdb-smoke 增加 x86_64 的
原生 GDB 冒烟与单进程 gdbserver 冒烟移植:

- 新增 build-x86_64-unknown-none.toml 与默认 qemu-x86_64.toml(native
  批量冒烟,成功标志 GDB_NATIVE_SMOKE_DONE);
- 补齐 gdbserver 全套:qemu-x86_64-gdbserver.toml(默认 gdbserver 冒烟,
  GDBSERVER_SMOKE_DONE)、gdbserver-host.toml、gdbserver-manual.toml,以及
  host-remote-x86_64.gdb / host-manual-x86_64.gdb(set architecture
  i386:x86-64);
- prebuild.sh 的 find_qemu_runner 增加 x86_64 分支(qemu-x86_64 +
  x86_64-linux-musl);
- README 补充 x86_64 native 与 gdbserver 用法。

gdbserver 路径依赖同分支的 x86_64 u_debugreg 偏移修复才能跑通。已在容器内
验证:native 冒烟 GDB_NATIVE_SMOKE_DONE、gdbserver 冒烟 GDBSERVER_SMOKE_DONE
均通过(断点/backtrace/continue/远程连接/正常退出全部正确)。

---------

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: 周睿 <34859362+ZR233@users.noreply.github.com>
Co-authored-by: 禾可 <chengkelfan@qq.com>
luodeb pushed a commit that referenced this pull request Jun 30, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR #1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

---------

Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
luodeb pushed a commit that referenced this pull request Jun 30, 2026
* feat(starry-kernel): x86_64 ptrace register r/w and PTRACE_SINGLESTEP support

补齐 x86_64 ptrace 主干功能:

- 新增 `X8664UserRegs` 结构体 (repr(C)),对应 Linux
  `user_regs_struct`,含 r15..rsp/ss/fs_base/gs_base 全部 27 个字段
- 实现 `From<UserContext> for X8664UserRegs` 和 `write_to()`
- 补齐 x86_64 上之前缺失的 ptrace opcode:
  GETREGS / SETREGS / GETREGSET(NT_PRSTATUS) / SETREGSET(NT_PRSTATUS) /
  GETSIGINFO / SETSIGINFO
- 将 `ptrace_getregset_prstatus` 中 `regs` 局部变量从内部 block 提升到
  函数级作用域,修复 reg_bytes slice 的 use-after-free bug(regs 出 block
  后被栈复用覆盖,导致用户态读到随机值,表现为 RSP=0x1)
- 新增 `ptrace_setup_singlestep` for x86_64:设置 RFLAGS 的 TF (bit 8)
  触发 CPU 单步执行

- 为 x86_64 添加 singlestep setup 调用(之前仅 riscv64)
- 新增 `ExceptionKind::Debug` 处理分支:命中 traced task 的 #DB
  异常时,清除 TF 并调用 ptrace_stop_current(SIGTRAP)
- Intel SDM 规定 CPU 在交付 TF 诱导的 #DB 时会清除 pushed RFLAGS
  中的 TF,但 QEMU 不完全遵守,故显式清除防止 resume 后再次单步

| 测试 | 验证内容 |
|------|----------|
| test-ptrace-x86-regs | TRACEME -> GETREGS/GETREGSET/SETREGS/SETREGSET 闭环 |
| test-ptrace-exec-stop | TRACEME + execve -> SIGTRAP + DETACH |
| test-ptrace-x86-breakpoint | 双测试:software int3 最小闭环 + SINGLESTEP 基础验证 |
| test-ptrace-x86-singlestep | PTRACE_SINGLESTEP 执行一条指令后以 SIGTRAP stop |
| test-ptrace-x86-breakpoint-reinsert | gdb 风格断点恢复:rewind RIP -> 恢复原字节 -> SINGLESTEP -> 重新插入断点 -> 再次命中 |
| test-gdb-native-batch | gdb -q -batch 端到端:break native_marker / run / bt / info registers / continue |

所有 6 个 x86_64 ptrace case 全部通过。

* feat(starry): add gdb smoke test app and update mount-umount2 compat docs

- apps/starry/gdb: gdb --version smoke test for x86_64 QEMU
  (qemu-x86_64.toml, build-x86_64-unknown-none.toml, prebuild.sh)
- docs: update mount-umount2 Linux compat documentation with
  shared/private/slave/unbindable propagation, bind subdirectory,
  MS_MOVE ELOOP, MS_REMOUNT|MS_BIND|MS_RDONLY semantics

* fix(starry-kernel): gate #DB handler behind #[cfg(target_arch = "x86_64")]

ExceptionKind::Debug and uctx.rflags only exist on x86_64, but the
Debug exception handler in user.rs had no cfg guard, leaking x86_64
single-step logic into all architecture builds.  Wrap the entire
block in #[cfg(target_arch = "x86_64")].

Fixes CI failures on loongarch64/aarch64/riscv64.

* test(starryos): extend gdb batch timeout

* test(starryos): isolate gdb apk install stage

* fix(starry-kernel): harden x86_64 ptrace reg writes

* fix(starryos): bundle gdb runtime for batch test

* fix(apps): replace docker-run gdb install with qemu-user + native apk

The prebuild script used 'docker run alpine:edge apk add gdb' which requires
the Docker daemon that is not available inside the CI container. Switch to
qemu-x86_64-static + native apk, consistent with gdb-smoke/prebuild.sh.

* fix(apps): use musl ld directly instead of qemu-user for same-arch x86_64 gdb install

qemu-x86_64-static hangs when emulating x86_64 binaries on an x86_64
host during network-heavy operations like 'apk' package downloads. Use
the musl dynamic linker (ld-musl-x86_64.so.1) from the staging rootfs
to run Alpine apk natively without any emulation layer.

* fix(apps): fix gdb app prebuild with musl ld and complete runtime assets

Replace docker-run-based gdb install with native musl ld execution
of Alpine apk, fixing DNS resolution for the staging root.

Add missing gdb/Python runtime assets to overlay:
- /usr/share/gdb/ (gdb Python modules, syscalls, system-gdbinit)
- /usr/lib/python3.12/ (Python stdlib)
- /usr/lib/python312.zip
- libpython3.12.so*
- /usr/bin/python3

* fix(apps): enable virtio-blk and virtio-net drivers for gdb app

The build config only had the 'qemu' feature which does not
automatically enable virtio drivers. Without ax-driver/virtio-blk,
the kernel cannot detect the root block device, causing:
  'failed to determine root device from available block devices'

Align with gdb-smoke's build config by adding the required
ax-driver/virtio-blk and ax-driver/virtio-net features.

* fix(apps): add missing virtio-gpu, virtio-input, virtio-socket features

Align gdb app build config with gdb-smoke and test-suit configs.

* fix(axbuild): handle symlinks in overlay injection via debugfs

CMake install(PROGRAMS ...) preserves symlinks from the staging
rootfs, which causes inject_overlay to fail with:
  'unsupported overlay entry ... only regular files and directories
   are supported'

When a symlink is encountered during overlay traversal, use debugfs
symlink command to create the symbolic link in the target ext4 image
instead of bailing out.

* chore(ci): trigger re-run

* chore(ci): trigger re-run 2

* fix(starry-kernel): add x86_64 ptrace FP register support (GETFPREGS/SETFPREGS/NT_FPREGSET)

* fix(axbuild): swap debugfs symlink args to link-path-first order

The debugfs symlink command expects "symlink <link_path> <target>"
matching mke2fs convention. Also harden the x86_64 ptrace test with
canary-fork cleanup detection and kernel fault regexes.

* fix(starry-kernel): detach live tracees when tracer exits

* fix(starry-kernel): align x86 ptrace fp snapshots

* fix(starry-kernel): stabilize x86 native gdb ptrace flow

* fix(starry-kernel): clean up ptrace gdb follow-up fixes

* fix(starry-mm): fix file_read_offset computation for unaligned COW split

When vaddr < file_vaddr_base (page-aligned-down start in
unaligned mappings), the saturating_sub returned 0 instead of
correctly subtracting the gap from file_start. This caused
wrong file data to be read after mprotect-induced VMA splits.

Fixes bug-unaligned-cow-split test failure on loongarch64.

* fix(starry-kernel): fix clippy manual_is_multiple_of warning

* fix(starry-mm): extend file_end to cover PT_TLS init image and add execve diagnostics

- map_elf(): scan PT_TLS segments and extend last PT_LOAD file_end
  so the COW backend can serve TLS init-image page faults for
  the dynamic linker. Without this, ldso sees zeroed TLS data
  on riscv64, leading to pc=0 crashes after execve.

- execve: add diagnostic logging for entry/sp/tp/ldso presence
  to help debug future user-mode startup failures.

* fix(starry-mm): add AT_NULL auxv terminator to prevent ldso out-of-bounds scan

The auxv constructed in ElfLoader::load() was missing the AT_NULL
(type=0) terminator that the musl dynamic linker uses to stop scanning.
Without it, ld-musl reads past the auxv array into environment string
data on the stack, interpreting arbitrary bytes as auxv entries.

The second exec in init.sh ("exec /bin/sh -l -i") inherits env vars
from the first shell, reshaping the stack so that the out-of-bounds
scan hits garbage aliasing AT_PHDR or AT_ENTRY, producing pc=0 SIGSEGV
with exit code 139. The first exec succeeds only by coincidence — its
empty envp produces a less harmful stack layout.

Fix: push AuxEntry::new(AuxType::NULL, 0) after AT_HWCAP to properly
terminate the auxv.

* chore(ci): re-trigger CI

* test(starry): add SIGSEGV detection to board test fail_regex patterns

OrangePi-5-Plus and SG2002 board tests were timing out after 300-600s
because SIGSEGV crashes (busybox mesg, busybox shell) were not caught
by fail_regex, so the runner waited for the full timeout instead of
failing fast.

Add three patterns to all board test TOMLs:
  - '(?i)segmentation fault'
  - '(?i)SIGSEGV'
  - 'exit with code: 139'

This ensures that any userspace SIGSEGV during boot/login is detected
immediately instead of being hidden behind a timeout.

* chore(ci): re-trigger CI after rustc segfault flake

* fix(starry-mm): add AT_NULL auxv terminator and execve/loader diagnostics

- ElfLoader::load(): add AuxType::NULL terminator to the auxv Vec
- Add info! diagnostic for entry/auxv_count/ldso/last_auxv_type
- execve: upgrade to info! with image name for crash correlation
- map_elf(): downgrade PT_TLS log to debug!

* fix(starry-mm): flush I-cache after populating executable pages on riscv64

On real hardware with non-coherent L1 I/D caches (T-Head C906 on
SG2002), a recycled physical frame from a prior exec may still
hold stale instruction-cache lines.  New code bytes written via
D-cache stores by the COW backend are invisible to the I-cache
unless fence.i is executed, causing the CPU to fetch garbage
instructions and jump to pc=0.

Add fence.i (flush_icache_all) in handle_page_fault after
populating any page with EXECUTE permission.  QEMU has no real
caches so this is a nop in simulation.

Also replace the stale 'TDOO: flush the I-cache' comment in
loader.rs with a note that coherence is now maintained at
fault time.

* fix(starry-mm): write back D-cache after populating executable pages on XuanTie C9xx

The SG2002 (T-Head C906) board test kept SIGSEGV-ing with pc=0 inside
ld-musl's _dlstart, even after the auxv terminator fix and an added
fence.i. Root cause: the C9xx L1 D-cache is write-back and `fence.i`
does not clean it to the point of unification. The COW backend writes
freshly-faulted code bytes into a frame through the cacheable kernel
linear mapping (phys_to_virt), leaving them in dirty D-cache lines.
The subsequent fence.i on user entry only invalidates the I-cache, so
the instruction fetch refills from stale memory and executes garbage,
jumping to 0. QEMU has no real caches, which is why it only fails on
the board.

- axcpu/riscv: add clean_dcache_range_to_pou(), a th.dcache.cva loop
  (per 64-byte line) followed by th.sync.s, gated on xuantie-c9xx.
  Opcodes 0x0295000b / 0x0190000b match Linux thead errata.c.
- cow backend: after populating/copying an executable page, clean the
  written kernel mapping to the PoU on riscv64 so the I-fetch (after the
  existing fence.i in UserContext::run) sees the new code.
- Drop the earlier ineffective fence.i in handle_page_fault; run()
  already issues fence.i before every user entry, and the missing piece
  was the D-cache writeback, not another I-cache invalidate.

* chore(starry-mm): dump full auxv and entry bytes for SG2002 crash triage

Temporary diagnostic: the SG2002 board still SIGSEGVs at pc=0 in
ld-musl _dlstart despite the cache-coherence fixes, and the entry
instructions execute (gp is set) before the jump to 0. To distinguish a
bad auxv (e.g. AT_ENTRY/AT_PHDR/AT_BASE) from corrupted loaded code
bytes, log every auxv entry and force-populate + hexdump the first 16
bytes at both the ldso entry and AT_ENTRY. To be reverted once root
cause is known.

* fix(starry-mm): read unaligned COW segment first page from correct file offset

The real cause of the SG2002 (and any dynamic-binary) pc=0 SIGSEGV in
ld-musl: commit 82b289c changed alloc_new_at()/file_info() so that when
vaddr < file_vaddr_base (the page-aligned-down first page of a segment
whose p_vaddr/p_offset is not page-aligned) the file offset was computed
as file_start - (file_vaddr_base - vaddr) instead of file_start.

For ld-musl the RW PT_LOAD is at vaddr=0x94b20 (holding .dynamic/GOT).
Its first page (0x94000) took the buggy branch and read the segment
bytes 0xb20 too early in the file, corrupting .dynamic/GOT. The dynamic
linker's RELATIVE self-relocation then produced garbage pointers and
jumped to 0 — deterministically, on the very first dynamic exec. The
ldso/app code pages themselves loaded fine (verified by dumping the
entry bytes), so this was never a cache-coherence problem.

The mapping invariant is simply: virtual address V maps to file offset
file_start + (V - file_vaddr_base). Restore the unified
`file_start + saturating_sub(vaddr, file_vaddr_base)` form (== the
pre-82b289cb1 code), which yields file_start for the unaligned first
page and the correct delta elsewhere. CowBackend::split keeps
file_vaddr_base/file_start intact, so the bug-unaligned-cow-split test
(which only reads page-aligned blob pages, all >= file_vaddr_base, via
the unchanged >= path) is unaffected.

Also revert the speculative XuanTie D-cache writeback and the auxv/byte
diagnostics added while chasing the wrong (cache) hypothesis.

* chore(ci): trigger CI after sync with main

* chore(starry): add proc maps area diagnostics for bug-proc-maps-lseek-refresh

* fix(starry): fix bug-proc-maps-lseek-refresh test failure

Two fixes:
1. pseudofs/proc: render_thread_maps() used '?' on backend.file_info()
   which aborted the entire area iteration when an area had no name
   or file backing (e.g. PROT_NONE guard pages).  Use
   unwrap_or_else() with a default-empty BackendFileInfo instead
   so all VMAs always appear in /proc/self/maps.

2. test/proc-maps: the test's has_vma_prefix() used %08lx which
   produces 8-hex-digit addresses, but the kernel uses {:016x}
   (16 hex digits on 64-bit).  Use %0*lx with addr_width =
   sizeof(void*)*2 to match the kernel's output format.

* fix: resolve merge conflicts with upstream/dev PR #1167

- Remove duplicate ProcMemFile (old WeakAxTaskRef version)
- Remove duplicate 'mem' node in ThreadDir
- Accept upstream per-TID ptrace refactor for task/mod.rs, signal.rs, user.rs
- Keep our render_thread_maps file_info() unwind fix

* fix: complete per-TID ptrace API migration and execve stop semantics

- ptrace.rs: migrate x86_64 FP regset paths from old process-wide
  ptrace_stop_fp_data()/set_ptrace_stop_fp_data() to per-TID
  ptrace_stop_fp_data_for(tid)/set_ptrace_stop_fp_data_for(tid, ...)
  using raw [u64;32] bytes to bridge FxsaveArea ↔ arch-independent
  PtraceStopRecord storage.

- execve.rs: fix PTRACE_TRACEME exec-stop semantics. Linux requires
  TRACEME'd tasks to always generate a SIGTRAP stop on execve;
  PTRACE_O_TRACEEXEC only controls whether the stop carries
  PTRACE_EVENT_EXEC.  Move the TRACEME check outside the TRACEEXEC
  option gate.

- reports: fix trailing whitespace and EOF blank lines for
  diff --check compliance.

* fix(starry-kernel): correct x86_64 ptrace single-step, exec-stop and register reporting

- user.rs: arm x86_64 hardware single-step (RFLAGS.TF) for traced tracees, and
  route the resulting #DB to a SIGTRAP ptrace-stop that disarms the per-TID
  single-step flag and clears the saved TF (the CPU pushes EFLAGS with TF still
  set), so a subsequent PTRACE_CONT runs free instead of single-stepping.
- axcpu/x86_64/trap.rs: drop the panic on an unhandled #DB; let it fall through
  to the user-space exception loop (kprobe/uprobe debug handlers still win).
- ptrace.rs: report Linux-convention user selectors cs=0x33/ss=0x2b via
  GETREGS/GETREGSET and accept them in SETREGS so debuggers detect a 64-bit
  inferior instead of i386; correct the single-step TF comment.
- execve.rs: every ptrace tracee stops with SIGTRAP on execve (PTRACE_O_TRACEEXEC
  only controls the event payload, not whether the stop occurs).
- proc.rs: drop a duplicate /proc/<pid>/mem entry in the thread dir listing.

* test(starry): convert test-gdb-native-batch to a raw-ptrace tracer

Replace the real /usr/bin/gdb driver with a self-contained raw-ptrace tracer
(matching riscv's test-ptrace-gdb), validating the kernel's ptrace on a
dynamically-linked process across execve and ld-musl startup without depending
on GDB's startup probes or target-description negotiation:

  fork + PTRACE_TRACEME + execve(dynamic target) -> exec-stop -> read AT_ENTRY
  from /proc/<pid>/auxv -> plant INT3 at AT_ENTRY -> PTRACE_CONT (ld-musl runs
  fully under ptrace) -> trap at the application entry -> restore + single-step
  -> PTRACE_CONT to exit 0.

- add c/src/tracer.c; CMakeLists builds both the dynamic target and the tracer
- qemu-x86_64.toml runs the tracer; success "DONE: N pass, 0 fail"
- remove gdb-native-batch.gdb, run-gdb-native-batch.sh, prebuild.sh (no gdb)

* test(starry): migrate x86 ptrace/gdb cases into grouped system and fix exec-stop path

Move 5 x86 ptrace/gdb test cases from undiscovered normal/qemu-smp1/ to
qemu-smp1/system/ with arch-filtered CMakeLists that install into
starry-test-suit, making them participate in the grouped CI runner.

- test-ptrace-x86-regs: remove canary fork, return exit code directly
- test-ptrace-x86-breakpoint: fix printf format string
- test-gdb-native-batch: split into tracer (starry-test-suit) and
  target (usr/bin), rename to test-gdb-native-batch-tracer

Promote test-ptrace-exec-stop from starry-known-fail / riscv-only to
starry-test-suit on riscv64|x86_64. Fix hardcoded path by using
/proc/self/exe so the re-exec child finds itself under the grouped
install location.

Delete stray test-ptrace-exec-stop/qemu-x86_64.toml (double discovery).

Verified: x86_64 and riscv64 grouped system both PASS, all ptrace
binaries show STARRY_SYSTEM_TEST_PASSED.

* chore(ci): re-trigger CI after roc-rk3568 board u-boot flake

* ci: trigger test run

* ci: trigger test run

* chore: remove accidentally committed internal ptrace/gdb reports

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(axbuild): tolerate slow guests in host HTTP test server

The apk-curl-equivalence system case downloads a 20MB payload from the
host HTTP server. The server used a 1s per-write timeout and silently
discarded write errors, so whenever a slow guest (notably x86_64, the
slowest QEMU guest) applied TCP backpressure for over a second, the body
write timed out, the error was dropped, and the connection was closed
mid-stream. curl then failed with "(18) end of response with N bytes
missing", flaking the x86_64 starry qemu test.

Raise the body write timeout to 30s (still finite so a wedged guest
cannot block the server thread and its Drop/join forever) and surface
write errors instead of swallowing them.

* test(starry): wire x86 ptrace/gdb cases into grouped system runner

The new x86_64 ptrace/gdb system cases were laid out as
system/<case>/c/CMakeLists.txt + c/src/, but the qemu-smp*/system
grouped runner builds one root CMake project that only add_subdirectory()
each subcase whose CMakeLists.txt sits directly under system/<case>.
As a result these cases were never built/installed in aggregate runs and
`-c qemu-smp1/system/<case>` failed at configure time with
"unknown grouped C subcase".

Move each case to the flat system subcase layout required by
test-suit/starryos/GUIDE.md (CMakeLists.txt + src/ at the case root) and
fix the relative include of common/starry_arch_filter.cmake accordingly.
Install destinations are unchanged.

Cases: test-ptrace-x86-regs, test-ptrace-x86-breakpoint,
test-ptrace-x86-breakpoint-reinsert, test-ptrace-x86-singlestep,
test-gdb-native-batch.

* fix(starry-kernel): rebase x86_64 ptrace onto upstream/dev per-tid baseline

Replace ptrace.rs with upstream/dev version as baseline and port x86_64 code:
- Add X8664UserRegs struct + From<UserContext>/write_to/sanitize_eflags
- Add X86_64_USER_* constants + peeksuser/pokeuser/user_area_x86_64
- Add x86_64 getregs/setregs/getfpregs/setfpregs/getregset/setregset impls
- Add ptrace_setup_singlestep for x86_64 (RFLAGS.TF)
- Wire x86_64 into multi-arch dispatch gates (NT_FPREGSET/NT_PRSTATUS)
- Define x86_64 PtraceStopFpData as tuple struct + real fxsave/fxrstor
- Add x86_64 to signal.rs ptrace FP save and mod.rs save/restore

Fixes three build-blocking issues:
- ptrace_restore_singlestep_insn present for all archs (from upstream baseline)
- ptrace_setup_singlestep present for aarch64/loongarch64 (from upstream baseline)
- x86_64 FP type matches between ptrace.rs and mod.rs (tuple struct)

* fix(starry-kernel): store full FxsaveArea in x86_64 PtraceStopFpData

Replace PtraceStopFpData([u64; 32], usize) with PtraceStopFpData(FxsaveArea)
to match the 512-byte FXSAVE area. Fixes out-of-bounds memory access at
4 call sites where from_raw_parts(ptr, 512) was created from a 256-byte
[u64; 32] array — UB when the slice exceeded the allocation.

save/restore/GETFPREGS/SETFPREGS/NT_FPREGSET now directly copy the full
FxsaveArea, preserving all XMM/MXCSR state.

* fix(starry): downgrade loader/execve logs to debug, restore kernel #DB panic, add TLS contiguity comment

* test(starry): add x86_64 ptrace FP register coverage

Exercises PTRACE_GETFPREGS/SETFPREGS and NT_PRFPREG round-trip on x86_64,
checking xmm0, xmm10 (offset 320) and xmm15 (offset 400) so a regression that
preserves only part of the 512-byte FXSAVE area is caught. The child loads
known XMM values and stops via a direct kill() syscall to avoid libc clobbering
the registers; the tracer verifies the read-back, writes sentinels, and the
child confirms them after resume. Auto-discovered under qemu-smp1/system.

* fix(starry-kernel): remove duplicate ptrace_setregset_prstatus, fix axnet typo and register call

* chore: fmt execve.rs register call

* fix(starry-kernel): remove unused VirtAddr and DirectRwFsFileOps imports in proc.rs

* chore: fmt proc.rs import line

* fix(starry-kernel): gate format_statm/format_status_vm_lines with cfg(test)

* fix(starry-kernel): gate alloc::format import with cfg(test)

* chore: reorder stats.rs imports for fmt

* fix(starry-kernel): scope ptrace get/setfpregs cfg to all non-x86 arches

ptrace_getfpregs/ptrace_setfpregs use the generic ArchFpRegs path for the
non-x86 architectures, but the supported arm was gated on
any(riscv64, loongarch64) (missing aarch64) while the Unsupported fallback
was gated on not(any(riscv64, x86_64)). On loongarch64 both arms matched,
causing E0428 (duplicate definition); on aarch64 the function fell through
to the Unsupported stub instead of the real ArchFpRegs path. Widen the
supported arm to any(riscv64, aarch64, loongarch64) and the fallback to
not(any(riscv64, aarch64, loongarch64, x86_64)), matching get/setregs.

* fix(starry-kernel): restore /proc features dropped by a bad merge revert

During an earlier conflict resolution, pseudofs/proc.rs was reverted to a
pre-refactor version, silently dropping upstream features: /proc/<pid>/mem
(ProcMemFile + read_at/write_at/check_access), /proc/<pid>/status memory
stats (sample_mem_stats, TaskStatusBase/TaskStatusFields) and the namespace
directory (NsDir), plus their tests. Restore the current upstream/dev proc.rs
and re-apply the only two genuine branch-local tweaks on top: the extended
loongarch /proc/cpuinfo Feat flags, and /proc/<pid>/maps full-width addresses
with anonymous-mapping file_info tolerance.

* fix(axbuild): restore upstream overlay symlink injection

An earlier divergence replaced the two-pass overlay debugfs injection with a
single-pass variant, dropping two upstream behaviours: deferring symlink
creation until after their targets are written (debugfs validates the target),
and converting relative symlink targets to absolute guest paths. Restore the
upstream/dev implementation (which already uses link-path-first symlink args).

* fix(starry-kernel): un-gate ProcessMemStats format methods for /proc

format_statm and format_status_vm_lines had been marked #[cfg(test)] back when
the reverted proc.rs no longer called them (to avoid dead_code under -D warnings).
The restored proc.rs uses both in the real build (/proc/<pid>/statm and
/proc/<pid>/status), so the test-only gating broke non-x86 builds with E0599.
Restore upstream/dev stats.rs so the methods are available in all builds.

* chore: remove accidentally committed GitHub page snapshot

A 172KB GitHub page snapshot (Feat_x86 64 ptrace clean ... rcore-os_tgoskits@f4d00dd.html)
was swept into the branch by a stray 'git add .'. It is not source/test asset and
makes 'git diff --check' fail on trailing whitespace/EOF blank lines. Remove it and
gitignore these page snapshots so they cannot be re-committed.

* fix(starry): use STARRY_ROOTFS in gdb app prebuild

starry app qemu injects the rootfs image path as STARRY_ROOTFS, not
STARRY_BASE_ROOTFS, so the gdb prebuild failed require_env and the
GDB_SMOKE_PASSED qemu path never ran. Match the ffmpeg/pip/mosquitto apps:
read ${STARRY_ROOTFS:-${STARRY_BASE_ROOTFS:-}} and require STARRY_ROOTFS.

* refactor(starry-kernel): converge x86_64 GP registers into ArchUserRegs explicit-TID backend

- Add ArchUserRegs alias for x86_64
- Make write_to return AxResult<()> for all archs
- Expand generic read/write backends to cover x86_64
- Remove parallel x86_64 helper functions
- Unify getregs/setregs into single generic bodies
- Remove inline arch dispatch from getregset/setregset_prstatus
- Update PEEKUSER/POKEUSER user-area to generic backend
- Remove redundant selected-stop wrappers from detach_live_tracees_of

* fix(starry): use dynamic platform for gdb x86_64 app build config

The gdb app x86_64 build config pinned the legacy static x86 platform
(ax-hal/x86-pc, ax-driver/plat-static, the qemu feature, plat_dyn=false).
x86_64 Starry runs on the dynamic platform path, which registers no static
platform package, so 'cargo xtask starry app qemu -t gdb --arch x86_64'
failed at build-config with 'no default platform package is registered for
arch x86_64' and the GDB_SMOKE_PASSED path was unreachable. Drop the static
deps and match the other Starry x86_64 app configs (git/top): keep only the
virtio driver features on the dynamic platform. Verified end-to-end in the
container: boots to a shell, gdb 16.3 runs, GDB_SMOKE_PASSED.

* chore(repo): remove unused workspace crates (#1306)

* feat(axbuild): internalize Starry kallsyms flow (#1309)

* fix(ci): bump smoke-vmx QEMU timeout 180→600s for self-hosted KVM runner (#1315)

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>

* fix(starry): correct x86_64 u_debugreg offset in struct user

x86_64 PTRACE_PEEKUSER/POKEUSER on the debug-register area used
X86_64_USER_DEBUGREG_OFFSET = 912, but u_debugreg[] sits at offset 848 in
the x86_64 `struct user` (regs 216 + u_fpvalid/pad 8 + i387 512 + tsize/
dsize/ssize 24 + start_code/start_stack 16 + signal 8 + reserved/pad 8 +
u_ar0 8 + u_fpstate 8 + magic 8 + comm 32 = 848).

gdbserver probes the hardware debug registers (DR0–DR7) via PEEKUSER at
this offset during startup; with the wrong offset it read a bogus location
and stalled before printing "Listening on port 1234", so the x86_64
gdbserver smoke hung. The native single-process GDB smoke does not touch
debug registers, which is why only the gdbserver path was affected.

Fix the offset to 848. Verified end-to-end in the container: the x86_64
gdbserver smoke now reaches GDBSERVER_SMOKE_DONE.

* feat(gdb-smoke): port GDB and gdbserver smoke to x86_64

参照现有 riscv64/aarch64/loongarch64 实现,为 gdb-smoke 增加 x86_64 的
原生 GDB 冒烟与单进程 gdbserver 冒烟移植:

- 新增 build-x86_64-unknown-none.toml 与默认 qemu-x86_64.toml(native
  批量冒烟,成功标志 GDB_NATIVE_SMOKE_DONE);
- 补齐 gdbserver 全套:qemu-x86_64-gdbserver.toml(默认 gdbserver 冒烟,
  GDBSERVER_SMOKE_DONE)、gdbserver-host.toml、gdbserver-manual.toml,以及
  host-remote-x86_64.gdb / host-manual-x86_64.gdb(set architecture
  i386:x86-64);
- prebuild.sh 的 find_qemu_runner 增加 x86_64 分支(qemu-x86_64 +
  x86_64-linux-musl);
- README 补充 x86_64 native 与 gdbserver 用法。

gdbserver 路径依赖同分支的 x86_64 u_debugreg 偏移修复才能跑通。已在容器内
验证:native 冒烟 GDB_NATIVE_SMOKE_DONE、gdbserver 冒烟 GDBSERVER_SMOKE_DONE
均通过(断点/backtrace/continue/远程连接/正常退出全部正确)。

---------

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
Co-authored-by: 54dK3n <ken@kendeAir.lan>
Co-authored-by: 54dK3n <ken@kendeMacBook-Air.local>
Co-authored-by: 54dK3n <ken@ac-c9-06-23-1e-48.walkup.net.uq.edu.au>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: 周睿 <34859362+ZR233@users.noreply.github.com>
Co-authored-by: 禾可 <chengkelfan@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants