Skip to content

Feat/gdb smoke x86 64 native#1330

Merged
ZR233 merged 75 commits into
rcore-os:devfrom
54dK3n:feat/gdb-smoke-x86_64-native
Jun 21, 2026
Merged

Feat/gdb smoke x86 64 native#1330
ZR233 merged 75 commits into
rcore-os:devfrom
54dK3n:feat/gdb-smoke-x86_64-native

Conversation

@54dK3n

@54dK3n 54dK3n commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

No description provided.

54dK3n and others added 30 commits June 17, 2026 21:14
… 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 全部通过。
…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
…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.
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.
…6_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.
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
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.
Align gdb app build config with gdb-smoke and test-suit configs.
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.
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.
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.
…ecve 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.
…unds 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.
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.
…tics

- 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!
…scv64

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.
54dK3n and others added 19 commits June 17, 2026 23:03
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.
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.
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).
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.
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.
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.
…gs 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
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.
…ner (rcore-os#1315)

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
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.
参照现有 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/远程连接/正常退出全部正确)。

@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 为 gdb-smoke 应用添加 x86_64 支持,并修复 X86_64_USER_DEBUGREG_OFFSET 常量值。

变更内容

  1. gdb-smoke x86_64 支持(8 个文件新增,2 个文件修改):

    • 新增 qemu-x86_64.tomlqemu-x86_64-gdbserver.tomlqemu-x86_64-gdbserver-manual.tomlqemu-x86_64-gdbserver-host.toml 四个 QEMU 配置
    • 新增 build-x86_64-unknown-none.toml 构建配置
    • 新增 host-manual-x86_64.gdbhost-remote-x86_64.gdb GDB 脚本
    • 更新 prebuild.sh:添加 x86_64 架构支持和 find_gcc_install_dir() 用于定位 GCC crt 对象
    • 更新 README 添加 x86_64 使用说明
  2. ptrace 常量修复(1 行变更):

    • X86_64_USER_DEBUGREG_OFFSET 从 912 改为 848

代码审查

  • 所有新增 QEMU 配置和 GDB 脚本均遵循现有 riscv64/aarch64/loongarch64 的模式,结构一致。
  • prebuild.shfind_gcc_install_dir() 逻辑清晰,查找 crtbeginT.o 所在目录用于 x86_64 musl 链接。
  • X86_64_USER_DEBUGREG_OFFSET 修改是正确的:在 Starry 自定义的 user area 布局中,u_comm 结束于 816 + 32 = 848,debugreg 应从 848 开始。旧值 912 与布局不一致。
  • 注意:此偏移量(848)与 Linux 标准 struct useru_debugreg 的偏移量(344)不同,这是 Starry 在 user area 中内嵌完整 FP 状态(512 字节)的设计决策,非本 PR 引入。

CI 状态

  • Detect changed paths:✅ 成功
  • Cancel stale CI runs:✅ 成功
  • Run sync-lint / run_container:✅ 成功
  • Check formatting / run_host:进行中(本地 cargo fmt --check 已通过)
  • 其他 container/publish 任务:跳过(符合 host/container 矩阵分流预期)

CI 无失败项。sync-lint 已通过,格式检查进行中但本地验证通过。

本地验证

  • cargo fmt --check:✅ 通过

重复/重叠分析

  • 检查了 open PR 列表,无其他 PR 涉及 gdb-smoke x86_64 支持。
  • PR #1329 修改 components/axcpu/src/x86_64/context.rs(FxsaveArea 的 XSAVE 支持),与本 PR 无文件冲突。

测试覆盖

PR 仅添加 app 配置和一个常量修复,未新增 test-suit 用例。根据 commit 历史,作者已在前序提交中验证了 6 个 x86_64 ptrace 测试用例全部通过。app 层面的 QEMU 运行验证需要 cargo xtask starry app qemu -t gdb-smoke --arch x86_64,由于环境限制无法本地运行,但配置与现有架构一致。

结论

PR 代码清晰,遵循现有模式,CI 无阻断性失败。建议 APPROVE。

Powered by mimo-v2.5-pro

@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 为 gdb-smoke 应用添加 x86_64 native 支持,并修复 X86_64_USER_DEBUGREG_OFFSET 常量值。

变更内容

  1. gdb-smoke x86_64 支持(8 个文件新增,2 个文件修改):

    • 新增 4 个 QEMU 配置:qemu-x86_64.tomlqemu-x86_64-gdbserver.tomlqemu-x86_64-gdbserver-manual.tomlqemu-x86_64-gdbserver-host.toml
    • 新增 build-x86_64-unknown-none.toml 构建配置
    • 新增 host-manual-x86_64.gdbhost-remote-x86_64.gdb GDB 脚本
    • 更新 prebuild.sh:添加 x86_64 架构支持和 find_gcc_install_dir() 用于定位 GCC crt 对象
    • 更新 README 添加 x86_64 使用说明
  2. ptrace 常量修复(1 行变更):

    • X86_64_USER_DEBUGREG_OFFSET 从 912 改为 848

代码审查

  • 所有新增 QEMU 配置遵循现有 riscv64/aarch64/loongarch64 的模式,结构一致。x86_64 使用 cpu maxto_bin = false,合理。
  • prebuild.shfind_gcc_install_dir() 逻辑清晰,查找 crtbeginT.o 所在目录用于 x86_64 musl 链接。-B/-L 标志对所有架构安全(冗余但无害)。
  • X86_64_USER_DEBUGREG_OFFSET 修复正确:在 Starry 自定义的 user area 布局中,X86_64_USER_COMM_OFFSET = 816X86_64_USER_COMM_SIZE = 32,因此 debugreg 应从 816 + 32 = 848 开始。旧值 912 = 848 + 64 实际上是 debugreg 数组的末尾而非起始位置,这是一个确认的 bug。
  • GDB 脚本设置 architecture i386:x86-64,正确。
  • 注意:此偏移量(848)与 Linux 标准 struct useru_debugreg 的偏移量(344)不同,这是 Starry 在 user area 中内嵌完整 FP 状态(512 字节)的设计决策,非本 PR 引入。

CI 状态

  • Check formatting / run_host:✅ 成功
  • Run sync-lint / run_container:✅ 成功
  • Detect changed paths:✅ 成功
  • Cancel stale CI runs:✅ 成功
  • 多项 QEMU 测试已通过(arceos x86_64/loongarch64/riscv64, axvisor aarch64/riscv64/loongarch64)
  • 16 项检查仍在运行中,无任何失败

重复/重叠分析

  • PR #1329 修改 components/axcpu/src/x86_64/context.rs(XSAVE 支持),与本 PR 无文件冲突。
  • 未发现其他 PR 涉及 gdb-smoke x86_64 支持或相同 ptrace 修复。

测试覆盖

PR 主要是 app 配置和一个常量修复。debugreg 偏移修复由 gdb-smoke x86_64 native 测试间接验证(完整的 ptrace 调试流程)。App 层面的 QEMU 运行验证需要 cargo xtask starry app qemu -t gdb-smoke --arch x86_64,CI 已有相关 QEMU 测试正在运行。

结论

PR 代码清晰,遵循现有模式,debugreg 偏移修正正确且关键,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.

本轮复查的是当前 head d035b375f994b74a5b396de0ef38ba36b8610663

这个 PR 的实际变更面比较集中:为 apps/starry/gdb-smoke 补齐 x86_64 native GDB 与单进程 gdbserver 的 QEMU 配置、host GDB 脚本和 prebuild 支持,同时把 x86_64 struct user 中 debug register 区域的 PTRACE_PEEKUSER/POKEUSER 偏移从 912 修正为 848。按当前代码里的 user-area 布局,X86_64_USER_COMM_OFFSET 为 816、长度 32,因此 debug register 起点是 848;旧值 912 实际越过了 8 个 debug register slot。这个修正也和 gdbserver 启动时探测 DR0-DR7 的行为相匹配。

测试覆盖方面,这里属于 app/QEMU workflow 变更,不能只看格式或普通 CI。我在隔离 worktree 中跑了文档新增的两个 x86_64 路径:

  • cargo xtask starry app qemu -t gdb-smoke --arch x86_64:通过,QEMU 内命中 GDB_NATIVE_SMOKE_DONE,覆盖断点、backtrace、info proc mappings/files/auxv、寄存器读取、内存查看、stepi 和正常退出。
  • cargo xtask starry app qemu -t gdb-smoke --arch x86_64 --qemu-config qemu-x86_64-gdbserver.toml:通过,QEMU 内命中 GDBSERVER_SMOKE_DONE,能看到 gdbserver Listening on port 1234、host GDB 连接、断点命中、backtrace、continue 和 tracee 正常退出。

两次 prebuild 中 debugfs rdump 打印了若干 root-owned 文件 ownership preservation 警告,但命令最终成功完成 overlay 注入、内核构建和 QEMU 运行;这些警告没有影响本次 app workflow 的通过条件。

当前 head 的远端 CI 也已通过相关常规覆盖:Check formatting / run_hostRun clippy / run_hostRun sync-lint / run_containerTest starry x86_64 qemu / run_container 以及其它 ArceOS/Axvisor/Starry QEMU 和 self-hosted board 检查均为 pass,container/host 互斥矩阵中的 skipped 项属于预期分流。

重复和重叠检查:base 分支已有 riscv64/aarch64/loongarch64 的 gdb-smoke 路径,以及旧的 x86_64 debugreg 偏移 912;没有等价的 x86_64 gdb-smoke/gdbserver 配置。相关 open PR 中 #1314 也触及 x86_64 ptrace/GDB,但它是更广的后续语义收敛,包含 FP regset 共用、single-step 状态清理、统一 test-ptrace-gdb、以及 debug register 写入能力边界调整;与本 PR 的 x86_64 app 配置和 debugreg offset 修复属于部分重叠/后续整合关系,不构成本 PR 的重复实现。后续若 #1314 合入,需要按当前 base/本 PR 结果解决语义合并,但不阻塞本 PR 当前变更。

未发现阻塞问题。测试位置也符合 app-support 规则:gdb-smoke 是 operator/app workflow,位于 apps/starry/gdb-smoke;本 PR 没有把 app workflow 放入 test-suit/starryos,并且实际 QEMU app 命令已在当前 head 验证通过。

@ZR233
ZR233 merged commit 1c188bc into rcore-os:dev Jun 21, 2026
52 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 18, 2026
This was referenced Jun 22, 2026
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.

* 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.

* 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.

3 participants