Files
MeowOS-For-R3P2/scripts/build/DEVKIT.md
T
AskaEth adaed09f94 fix(devkit): M24 r2 评审 — 交付完整性闸门 + 补 sysctl + time64 文档更正
P2-1(与 P1 同类):licenses/ 与 README 缺失仍会假成功。
- 新增 meta_complete()/verify_meta():MANIFEST + README + 五份许可证副本
  (procps COPYING/COPYING.LIB、ncurses、lsof、musl-COPYRIGHT)缺一即不完整
- 纳入 skip 条件与 --verify-only;产物未变但 meta 缺失时就地 write_meta 补全(不重编),
  构建树不在则退回全量重建
- 回归测试新增 T6(删 licenses 后 --with-sources 必须恢复)、T7(--verify-only 必须拒绝)、
  T8(删 README 后恢复);共 20 项全过

P2-2:README.txt/MANIFEST.txt 的卡上路径全错(写成 ../src、scripts/build/…)。
- 全部改为卡内相对路径:src/、licenses/、MANIFEST.txt、src/DEVKIT.md、src/build_devkit.sh
- README 增加「目录内容」段并注明 src/ 是生成目录、勿手放文件

P2-3:valgrind 的排除理由(“无 MIPS32 后端”)是错的 —— 官方支持 MIPS32/Linux。
- 改为「未尝试」:交叉构建需 autotools + 目标 vDSO 细节、产物 10MB+,56MB 单核不实用

P2-4:busybox 1.31 实测有 pgrep/kill/killall,没有 pkill、没有 sysctl。
- 表格改准确;pgrep 保留(增量有限不交付);pkill 写明「busybox 无此 applet,
  killall 只能部分替代,本轮未做」
- 新增交付 sysctl(procps 4.0.4,148184 B,静态):MANIFEST/verify-only/真机
  (sysctl -a 428 键、kernel.hostname/panic 读取、-n)均已验证

P2-5:free -s <小数> 也受 time64 影响(usleep 亚秒被抹平),文档说反了。
- DEVKIT §9 增加一行(free -s 0.5 实测 0s、free -s 1 实测 1s);README 同步;
  “收益只有 vmstat -t 一列”改为包含 free -s

P3:
1. §9 机制改准:内核只写 8 字节 → tv_sec 高 32 位是内核写入的 nsec、offset 8 的
   tv_nsec 才是未初始化;nanosleep 是把 tv_sec 高半字当 nsec 读(0)
2. 删掉脚本里 top 的旧错误归因(时长溢出/59.4 GiB),与 DEVKIT 对齐
3. 测试耗时改为「热缓存约 15s,冷启动 1–2 分钟」(实测 28s 含多次构建/修复路径)
4. --verify-only 依赖清单写全(file/readelf/sha256sum/awk/sed/grep/wc/cut/basename)
5. licenses/ 增加 musl-COPYRIGHT(zig env → libc/musl/COPYRIGHT,取不到即失败),§6 补一行
6. htop 说明改准:亚秒刷新走 ncurses halfdelay()(select + 32 位 timeval),大概率不受
   time64 影响;受影响的是时钟显示与部分采样(仍注明未做运行时验证)
7. README/脚本注明 src/ 是生成目录
8. LGPL 摘要改为「源码(§6a) 或 共享库(§6b) 或 书面要约(§6c)」
9. ltrace/sysstat 从「不可行」改为「未做(成本高)」,与 perf 的硬阻塞区分

验证:test_build_devkit.sh 20/20;--verify-only 通过(7 个二进制 + MANIFEST + 5 份许可证);
独立工作区离线重建 64s/0 下载,七个 sha256 与前一次逐字节一致;设备实测 sysctl 与其余六项正常。
2026-11-06 19:53:45 +08:00

307 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MeowOS devkit — 静态 MIPS32r2 调试工具集
TF 卡 `MeowOS/opt/devkit/bin/` 里那批静态二进制的构建说明、可行性实测、许可证留痕。
构建入口:`bash scripts/build/build_devkit.sh`;回归测试:`bash scripts/build/test_build_devkit.sh`
(热缓存约 15 秒;冷启动需先重建基线,1–2 分钟)。
产物在 `fw_apps/devkit/`,已被 `.gitignore` 的 `fw_apps/` 规则覆盖,不入库。
## 1. 为什么要有这个
设备(HiBy R3 Pro II / Ingenic X1600 / MIPS32r2 / Linux 4.4.94+ / 单核 / 56 MB)自带
busybox 1.31.1:`free / ps / top / lsof` 是 busybox 的软链(实测 `/bin/ps -> busybox`、
`/usr/bin/{free,lsof,top} -> ../../bin/busybox`),字段残缺;`vmstat`、`slabtop`、`pmap`、
`sysctl` **没有对应 applet**(`busybox --list` 实测:有 `pgrep`/`kill`/`killall`,无 `pkill`/`sysctl`)。
做内存分析时最缺的正是:
- `slabtop` —— Slab 总量 ~11 MB 到底被谁占了(buffer_head / dentry / squashfs_inode…)
- `vmstat` —— 系统级趋势(r/b、si/so、in/cs、us/sy/id/wa),busybox 无替代
- 真版 `lsof` —— busybox lsof 只有 pid/fd/设备号,没有 SIZE/OFF、TCP 状态、NAME
所以本工具集只围绕「这台机器的真实调试痛点」,不做大而全。
## 2. 产物清单
全部:`ELF 32-bit LSB executable, MIPS, MIPS32 rel2, statically linked, stripped`,
`readelf -d` 零 `NEEDED`(musl libc 静态链入),可直接从 exFAT 卡上跑。
| 工具 | 来源版本 | 许可证 | 体积(B) | 用途 / 相对 busybox 的增量 |
|---|---|---|---|---|
| `slabtop` | procps-ng 4.0.4 | GPL-2.0-or-later(依赖 libproc2 LGPL-2.1+) | 394 408 | Slab 明细;`-o` 一次性输出不需要 TTY/terminfo |
| `vmstat` | procps-ng 4.0.4 | 同上 | 216 924 | 系统趋势;busybox 无;`-t` 时间戳列本工具链下为空,见 §9 |
| `ps` | procps-ng 4.0.4 | 同上 | 324 980 | `-eo pid,rss,vsz,comm --sort=-rss` 等完整字段 |
| `pmap` | procps-ng 4.0.4 | 同上 | 173 460 | 地址空间映射(读 `/proc/pid/maps`);busybox 无 |
| `sysctl` | procps-ng 4.0.4 | 同上 | 148 184 | 读写 `/proc/sys`(`-a` 列出 428 个键);busybox 1.31 无此 applet |
| `free` | procps-ng 4.0.4 | 同上 | 94 312 | 拆 buff/cache、available |
| `lsof` | lsof 4.99.4 | Purdue/BSD-style | 789 496 | SIZE/OFF、TCP 状态、NAME、`-i` 网络视图 |
| | | **合计** | **2 141 764 ≈ 2.1 MB** | |
同目录还有 `MANIFEST.txt`(每个二进制的 sha256 + 版本 + 许可证 + 体积)、
`licenses/`(procps COPYING + COPYING.LIB、ncurses COPYING、lsof COPYING、**musl COPYRIGHT**)、
`README.txt`(上卡说明)。`--with-sources` 会额外生成 `src/`(三份源码包 + `build_devkit.sh` + 本文件)。
## 3. 上卡后怎么用
```sh
# 临时(SSH 会话)
export PATH=/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH
# 持久化:rootfs 的 /etc/profile.d/meow_card_path.sh 只前插了 MeowOS/opt/bin,
# devkit 是独立目录,需要再补一行(由塔/维护者决定是否进固件):
if [ -d /usr/data/mnt/sd_0/MeowOS/opt/devkit/bin ]; then
export PATH="/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH"
fi
```
**与 busybox 同名命令的先后关系**(前插 PATH 时):
| 名字 | 现状(实测) | 前插后 |
|---|---|---|
| `free` `lsof` `top` | `/usr/bin/x -> ../../bin/busybox` | `free`/`lsof` 解析到 devkit 版;`top` 仍是 busybox(本工具集不提供) |
| `ps` | `/bin/ps -> busybox` | 解析到 devkit 版 |
| `vmstat` `slabtop` `pmap` `sysctl` | 不存在(busybox 无对应 applet) | 新增 |
要临时用回 busybox 版:`busybox free`、`busybox ps`、`busybox lsof`。
不要覆盖 `/usr/bin`、`/bin` 里的软链:rootfs 是 ubifs,随固件回刷即被还原,而且这些软链是基线的一部分。
## 4. exFAT 语义(权限 / 软链)
设备挂载:`/dev/mmcblk0 on /usr/data/mnt/sd_0 type exfat (rw, fmask=0022, dmask=0022, symlink=0, noexec 未设置)`。
- **无符号链接**(`symlink=0`):本工具集全部是实体文件,不做 `argv[0]` 分派,也不提供 symlink
(不像 busybox 那样一个多合一二进制 + 一堆软链)。
- **无 Unix 权限位**:`fmask=0022` 让卡上新文件恒为 `0755`,因此**不需要 chmod**——
反过来说 `chmod` 在这里本身是 no-op;卡上也表达不了 setuid,任何需要 setuid 的工具都不适合放这。
- **可执行性**:挂载参数里没有 `noexec`,且卡上现有 `MeowOS/opt/MeowPanel/meowpanel` 就是 0755 直接执行的。
本轮真机验证是在设备 `/tmp`(同为 MIPS 目标、root 身份)做的,**没有往卡上写过任何东西**(约定:卡由塔推)。
## 5. 重跑代价与可复现性
- **联网次数**:冷启动 **3 次**(ncurses / procps-ng / lsof 各一个 tarball,共 5.5 MB);
源码包按 sha256 校验后落在 `$MEOW_DEVKIT_WORK/src/`,此后**重跑 0 次联网**。
- **耗时**(8 核宿主实测):冷启动(含 3 次下载)**80–86 秒**;源码已缓存时全量重编 **60–85 秒**;
`stamp` 命中(脚本、版本、zig 版本都没变)**2–3 秒**;回归测试热缓存 **约 15 秒**(冷启动基线另算)。
- **`--verify-only`**:只做静态/架构/NEEDED 检查 + MANIFEST 逐条 sha256/体积比对 +
MANIFEST/README/licenses 完整性检查。**不需要 zig、make、date、网络**;
实际依赖 `file`、`readelf`、`sha256sum`、`awk`、`sed`、`grep`、`wc`、`cut`、`basename`。
- **stamp 内容**:脚本 sha256 + zig 完整版本(0.17.0 / 0.17.1 会区分)+ target + 内核版本 + 三个上游版本。
- **可复现(逐字节)**:在两个不同工作区各建一次,七个二进制 **sha256 完全相同**
(`ps` 用 `-ffile-prefix-map` 抹掉绝对源码路径;`lsof` 用裸名 `CC=zigcc` + 相对源码路径,
不再把工具链/构建目录写进 `LSOF_CC/LSOF_CCFLAGS`)。`MANIFEST.txt` 里的 sha256 与设备上
`sha256sum` 的结果一致,可用来核对「跑的到底是哪个二进制」。
- **skip 的完整条件**:stamp 未变 **且** 七个 bin 通过静态/架构自检 **且** MANIFEST 与 bin 逐条一致
**且** MANIFEST/README/licenses 齐全。任一不满足就补(meta 缺失时直接重写 meta,不必重编)或重建。
## 6. 许可证与分发合规(重点)
| 上游 | 许可证 | 分发二进制时的义务 |
|---|---|---|
| procps-ng 4.0.4(apps) | **GPL-2.0-or-later** | **提供完整对应源码**(GPLv2 §3),含 "scripts used to control compilation and installation" |
| procps `library/`(libproc2) | **LGPL-2.1+** | `ps/vmstat/slabtop/free/pmap/sysctl` **静态链接**了它 → LGPL-2.1 §6 另有要求,见下 |
| ncurses 6.5 | MIT 风格(X11) | 保留版权与许可声明;只静态链入 slabtop,不单独分发 |
| lsof 4.99.4 | Purdue Research Foundation 许可(BSD 风格 4 条) | 文档与源码中保留作者/Purdue 署名;改过的版本要标注 |
| **musl**(zig 0.17 自带) | MIT | 七个产物都静态链入了它 → 随副本保留版权与许可声明(`licenses/musl-COPYRIGHT`) |
**GPLv2 §3**:`build_devkit.sh` 里的固定版本 + 下载 URL **不构成合规**。URL 作者可能撤、
镜像可能消失,而且 GPL 要求的是*分发者*提供的源码或书面要约。因此 `--with-sources` 会把
**三份源码包 + `build_devkit.sh` + 本文件**一起放进 `src/`(合计约 5.6 MB)。少一样都不算完整:
没有构建脚本,收卡人拿不到本轮用的 `configure`/`-D` 参数(这正是 "corresponding source" 明确包含的)。
**LGPL-2.1 §6(静态链接)**:六个 procps 工具静态链入 libproc2,除 GPL 义务外还必须
「显著提示使用了该库 + 附许可证副本 + 三选一」:
**(§6a)** 随作品提供该库的完整源码(含修改);
**(§6b)** 改用共享库机制(静态交付做不到);
**(§6c)** 书面要约(≥3 年)提供 §6a 的材料。
本工具集走 **§6a**:`src/procps-ng-4.0.4.tar.xz` 含 `library/` 全量源码,
`src/build_devkit.sh` 是本轮的唯一构建描述,`licenses/procps-ng-4.0.4-COPYING.LIB` 是许可证副本。
若想更保守(收卡人不想自己重编),可再额外提供可重链接的 `.o`(当前**未做**,属可选加固)。
**musl(MIT)**:MIT 要求在副本中保留版权与许可声明,因此 `licenses/musl-COPYRIGHT` 是必需项
(构建脚本从 `zig env` 的 `lib_dir/libc/musl/COPYRIGHT` 取,取不到直接失败)。
**结论**:内部自用不触发分发义务;但既然这批二进制可能被拷来拷去,建议一律
`--with-sources` 上卡。`licenses/` 只是声明留痕,**不能替代源码义务**。
## 7. 未交付清单(以及为什么)
| 候选 | 结论 | 原因 |
|---|---|---|
| `top`(procps 4.0.4) | **不交付** | 表头时钟被工具链 time64 问题打坏(显示 `-1202590843:00` 一类),无 TTY 时还会静默 `exit 1`。**不是 procps 的 bug**(r1 评审已更正我此前的错误归因),根因见 §9。卡上已有 htop,`top` 属重复 |
| `htop` | 不构建 | 卡上 `MeowOS/opt/bin/htop` 已是 **3.5.3**(673 744 B)。实测用 zig + 自编 ncursesw 也能编出 3.5.3,但 strip 后 **756 908 B**,比现有版本更大(静态链 musl+ncurses)。**未做运行时验证**;按代码路径,它的亚秒刷新走 ncurses `halfdelay()`(内部 `select()` + 32 位 `struct timeval`),**大概率不受 §9 的 time64 影响**,真正会受影响的是时钟显示(`localtime_r`/`clock_gettime`)与部分采样 |
| `watch` | 不构建 | busybox 1.31 已有 `watch`;procps 版 403 KB,收益不抵体积 |
| `pgrep` | 不构建 | busybox 已有 `pgrep`;procps 版 260 KB(链接整份 libproc),增量有限 |
| `pkill` | **不构建** | busybox **没有** `pkill` applet(只有 `kill`/`killall`,`killall` 只能部分替代);procps 版 260 KB,本轮未做 |
| `uptime`/`tload`/`pidof`/`pidwait`/`w` | 不构建 | busybox 已有 `uptime`/`pidof`;`tload`/`w` 在本机无调试价值 |
| `perf` | 不可行 | 依赖目标内核源码树(`tools/perf` 要按内核版本配 `perf_event_attr`),没有内核头,属硬阻塞 |
| `valgrind` | **未尝试** | valgrind **支持 MIPS32/Linux**(官方平台页有 MIPS32/MIPS64),所以不是「无后端」;但交叉构建需 autotools 工具链 + 目标内核/vDSO 细节,产物通常 10 MB+,在 56 MB 单核设备上不实用。本轮未做可行性验证 |
| `ltrace` | **未做(成本高)** | 需要 libelf + 复杂 autoconf 探测,且本机程序多为静态/精简;属投入产出判断,不是「不可能」 |
| `sysstat`(sar/iostat/mpstat) | **未做(成本高)** | autoconf 探测多、依赖 `gettext`/`libsensors` 等;本机单核、`/proc/diskstats` 对 TF 卡意义有限 |
| `gdb` | 不建议 | 设备已带 `gdbserver`,宿主侧可用交叉 gdb 连;在 56 MB 单核设备上跑 gdb 本体收益极低、体积巨大 |
| `smem` | 价值为零 | 依赖 `/proc/<pid>/smaps` 的 PSS,本机没有 smaps |
`pmap` 的低价值要说明白:本机 `CONFIG_PROC_PAGE_MONITOR=n`,`/proc/<pid>/smaps` 不存在,
所以 `pmap -x` 拿不到 PSS/私有脏页。它仍有用的一点是 `/proc/<pid>/maps` **存在**,
`pmap <pid>` 能列出地址段 + 映射文件名(busybox 没有等价物),排查「谁映射了这块内存」够用。
## 8. 可行性实测记录(编不出来的卡在哪)
宿主:Termux/Android aarch64,zig 0.17.0(自带 musl libc 与头文件),`make`、`curl`、`pkg-config`。
**没有** autoconf/automake/libtool,**没有**目标内核头,sysroot 里只有 zlib(本工具集不需要它)。
- **procps-ng 4.0.4** ✅ 可编(vmstat/slabtop/free/ps/pmap/sysctl 全部产出)。三个必须处理的坑:
1. `slabtop`(`src/slabtop.c` 直接 `#include <ncurses.h>`)硬依赖 ncurses;
`configure --without-ncurses` 会把它整个跳过 → 要 `slabtop` 就必须先交叉编 ncurses。
2. 交叉编译下 autoconf 的 `malloc(0)/realloc(0)` 运行期探测无法执行,不缓存
`ac_cv_func_malloc_0_nonnull=yes ac_cv_func_realloc_0_nonnull=yes` 会引入
`rpl_malloc/rpl_realloc` 未定义引用,链接失败。
3. 必须把 `PKG_CONFIG_LIBDIR` 收紧到自编 prefix,否则会捡到宿主 aarch64 的
`ncursesw.pc`,结果是「musl 头 + bionic 头」混编(`watch` 直接编不过)。脚本里有事后断言。
- **ncurses 6.5** ✅ 可编(`--without-shared --with-normal --enable-widec --without-progs` 等)。
**必须** `--with-default-terminfo-dir=/usr/share/terminfo --with-terminfo-dirs=...`:
否则交互式 `slabtop` 会 `Error opening terminal: xterm.`(默认值是编译期 prefix,设备上不存在)。
体积代价:`libncursesw.a` 3.3 MB(未 strip,不单独分发),链进 `slabtop` 后只增加约 100 KB。
- **lsof 4.99.4** ✅ 可编。坑:
1. 4.99 源码包**不带** `configure`(autotools),但带老式 `Configure` 脚本,`./Configure -n linux` 可用。
2. 版本探测读宿主 `/usr/include/linux/version.h` + `uname`,交叉时拿不到 4.4.94,
会退化成 `LINUXV=00000 / LSOF_VSTR="0.0.0"`(Configure 打 "unsupported dialect or version")。
这两个宏在 linux dialect 里只影响 `lsof -v` 显示,仍用 `-DLINUXV/LSOF_VSTR` 覆盖成 4.4.94。
3. zig 的 musl 头没有 glibc 侧经由 `linux/tcp.h` 间接带来的 `TCP_ESTABLISHED` 等 11 个
状态宏,`dsock.c` 会编不过 → 脚本里 `-D` 补齐(值取自 `linux/tcp.h`)。
4. zig cc **不带 `-O` 时按 Debug 编**,会插入 UBSan 桩(`__ubsan_handle_negate_overflow`)
导致链接失败 → 所有编译都显式 `-O2`。
- **htop 3.5.3** ✅ 可编(用自编 ncursesw),strip 后 756 908 B —— 比卡上现有版本大,
且未做运行时验证,故不交付(见 §7)。
- **perf** ❌ 不可行:依赖目标内核源码树/头文件。
- **valgrind** ⚠️ 未尝试(支持 MIPS32/Linux,但交叉构建与体积/内存代价不划算;见 §7)。
- **ltrace** / **sysstat** ⚠️ 未做(成本高,见 §7)。
- **smem** ⚠️ 价值为零:依赖 smaps,本机没有。
## 9. 已知限制:工具链的 time64 在 4.4 内核上不可用
**这不是 procps/htop 的 bug,是 zig 0.17 自带 musl 在 mipsel 上的 ABI 错配**(r1 评审定根因,
我此前把 `top` 的表头问题误判成 procps bug,此处更正)。
机制(三段,均可复验):
1. zig 0.17 的 `mipsel-linux-musleabi` 是 **time64**:`sizeof(time_t)=8`、`sizeof(long)=4`,
`struct timespec` 16 字节;同时 clang 前端给 mips o32 预定义了 `__ILP32__`。
2. zig 自带 musl(`libc/musl/src/time/clock_gettime.c`、`time/clock_nanosleep.c` 等)的守卫写成
`#if defined(SYS_*_time64) && !defined(__ILP32__)`;上游 musl 1.2.5 没有这个 `!defined(__ILP32__)`。
3. MIPS o32 是 ILP32、内核 4.4 又没有 time64 syscall → 走 `#else` 分支,把 **16 字节的 time64 结构**
直接交给 **32 位 time32 系统调用**。内核按 `{int32 tv_sec; int32 tv_nsec}` 解释这 16 字节:
- `clock_gettime`:内核只写前 8 字节 → 调用者的 `tv_sec`(offset 0..7)= `sec | (nsec << 32)`,
**高 32 位是内核写入的 nsec**;而 offset 8 的 `tv_nsec` **完全没被写,保持未初始化**
(评审 memset 0xAA 实测读到 `nsec=0xAAAAAAAA`)。
- `gettimeofday` 同理:`tv_sec` 高半字是内核写入的 usec,offset 8 的 `tv_usec` 未初始化。
- `nanosleep`:内核把 `tv_sec` 的**高半字当 nsec 读**(小秒数时为 0),调用者真正的 `tv_nsec`
(offset 8)被忽略 → 亚秒被抹平、整秒正常。
真机实测(本轮):
| 现象 | 结果 | 影响 |
|---|---|---|
| `clock_gettime` / `time()` / `gettimeofday()` | rc=0 但值是垃圾(评审另测:`sec=2823213556008072608`,`localtime_r` 返回 NULL) | 任何按墙钟格式化时间的功能 |
| `vmstat -t` | 表头有 `-----timestamp-----`,**数据行该列整列为空**(`localtime()` 返回 NULL) | `vmstat` 核心的 3 组计数**正常**;只有时间戳列不可用 |
| `free -s 0.5 -c 2` | **实测 0 秒**(应约 0.5 秒):`free.c` 用 `usleep(interval)`,亚秒被抹平 | **小数间隔失效**;`free -s 1 -c 2` 实测 1 秒,正常 |
| `top` 表头时钟 | 显示 `-1202590843:00` 一类 | §7 不交付 top 的原因 |
| `usleep(0.5s)` ×10(独立探针) | **实测 0 秒**(应 5 秒) | 亚秒轮询会退化成空转 |
| `sleep(1)`(整秒) | 正常:`vmstat 1 3` 墙钟实测 2 秒、`vmstat 1 2` 实测 1 秒 | 整秒采样周期不受影响 |
| `ps -eo lstart` | 正常 | 时间来自 `/proc/stat` 的 `btime` + jiffies,不走 libc 取时 |
| `slabtop`/`pmap`/`sysctl`/`lsof` | 不受影响 | 不显示墙钟、也不做亚秒等待 |
**能否复用仓里已有的修复?** 有。M16 的 `patch_v2/sdk/meow_ui_time.c`(文档 `patch_v2/sdk/CLOCK_ABI.md`)
用「链接期强定义」接管了 `__clock_gettime` / `__clock_gettime64` / `__nanosleep_time64` /
`__clock_nanosleep(_time64)` / `__timedwait*` / `__timerfd_*` / `__clock_settime64`,
内部按内核 o32 time32 ABI 取数再升成 64 位。
- **可复用的证据(本轮实测)**:`zigcc -O2 -I. -Iinclude -c patch_v2/sdk/meow_ui_time.c` 单文件编译成功,
未定义符号只有 5 个 libc 符号(`__errno_location`、`__pthread_setcancelstate`、`__syscall_cp`、
`__udivdi3`、`syscall`),不依赖 SDK 其它目标文件。
- **代价**:必须把该 `.o` 放在 libc 之前参与链接(才会盖掉 libc 里那份),要给两套构建系统分别注入:
procps 走 libtool 的 `LDADD`、lsof 是手写 Makefile 的固定链接行;然后七个二进制全部重新真机验证。
估计 1–2 小时(含设备回归),产物每个 +几 KB。
- **本轮为什么不做**:收益是 `vmstat -t` 时间戳列 + `free -s <小数>` 两处(`top` 不交付、`ps` 本来正常、
其余不打时间),而这个改动会动到 libc 的取时/睡眠入口,风险面比收益大。
**结论:可复用,但需要单独一条 mission 做「接入 + 全量回归」**,不适合塞进修 P2 的补丁里。
- **不加 shim 的替代方案**:给 zig 的 musl 打补丁(去掉 `!defined(__ILP32__)`)或换上游 musl 工具链。
**这不是加一个 `-D` 能修的**:守卫在 libc 源码里,编译产物(libc.a)已经固定。
## 10. 路径清洁:lsof 里有一处宿主路径(工具链副作用)
`strings lsof` 有一处 `/data/data/com.termux/files/usr/etc/resolv.conf`(其余六个产物没有宿主路径)。
来源是 **Termux 打包的 zig 自带 musl**(`libc/musl/src/network/resolvconf.c` 被改成 Termux prefix),
不是 lsof 源码,也不是本脚本的路径泄漏(源码路径已用 `-ffile-prefix-map` 抹掉)。
- 设备上该路径不存在 → **真正的 DNS 反查会失败**;`lsof -i` 不带 `-n` 时会因此卡在超时(实测约 3 秒),
带 `-nP` 瞬时返回。
- 端口名/本机名不受影响(来自 `/etc/services`、`/etc/hosts`):实测 `lsof -i` 仍显示 `TCP *:ssh`、`UDP localhost:domain`。
- **结论**:不改。换成非 Termux 的 zig/上游 musl 需要重装工具链并重做全部验证,代价大而收益仅「反向 DNS」;
文档与 `README.txt` 已写明**用 `lsof -nP`**。
## 11. 真机验证证据(2026-11-06,root@10.76.208.50)
产物拷到设备 `/tmp`(tmpfs)执行,验证完已删除;**没有**往 TF 卡写过任何东西。
```
# slabtop -o | head -6
Active / Total Objects (% used) : 55852 / 61357 (91.0%)
Active / Total Slabs (% used) : 2794 / 2794 (100.0%)
Active / Total Caches (% used) : 57 / 81 (70.4%)
Active / Total Size (% used) : 11024.86K / 11593.48K (95.1%)
Minimum / Average / Maximum Object : 0.02K / 0.19K / 32768.00K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
12474 10746 86% 0.06K 198 63 792K buffer_head
# vmstat 1 3 (墙钟实测 2 秒,采样间隔正常)
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
1 0 0 2584 8764 19388 0 0 0 0 449 6 3 3 94 0 0 0
0 0 0 2644 8764 19388 0 0 0 0 340 566 1 5 94 0 0 0
0 0 0 2644 8764 19388 0 0 0 0 332 526 1 2 97 0 0 0
# free -m
total used free shared buff/cache available
Mem: 55 30 2 1 27 24
Swap: 0 0 0
# ps -eo pid,rss,vsz,comm --sort=-rss
PID RSS VSZ COMMAND
1368 4832 16516 meow_launcherd
4241 1608 3012 sh
...
# pmap 1
1: init
00400000 864K r-x-- busybox
004e8000 4K rw--- busybox
00969000 132K rwx-- [ anon ]
# sysctl -a | wc -l → 428(键数)
# sysctl kernel.hostname kernel.panic
kernel.hostname = meowos
kernel.panic = 10
# sysctl -n kernel.ostype → Linux
# lsof -nP -i (瞬时;不带 -n 约 3 秒,见 §10)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dropbear 1354 root 3u inet 2196 0t0 TCP *:22 (LISTEN)
meow_netm 1372 root 5u inet 2611 0t0 UDP 127.0.0.1:53
meow_mdns 1375 root 3u inet 2906 0t0 UDP *:5353
meowpanel 1395 root 3u inet 2587 0t0 TCP *:8080 (LISTEN)
```
- 七个二进制 `--help`/`-V` 全部正常(`lsof --help` 不是合法选项,`lsof -v` 打印 4.99.4)。
- 交互式 `slabtop`(无 `-o`)在 `TERM=xterm` 下正常初始化 curses(stdout 写出 1599 字节转义序列);
对照 `TERM=bogus-term` 报 `Error opening terminal: bogus-term.` —— 说明 terminfo 路径确实命中
`/usr/share/terminfo`,不是内嵌 fallback。
- 设备上 `sha256sum` 与 `MANIFEST.txt` 逐条一致(测的就是交付的那份字节)。
- 宿主侧静态/架构自检、MANIFEST 对账、licenses 完整性:`bash scripts/build/build_devkit.sh --verify-only`。
## 12. 其它已知限制
- `pmap -x` 无 PSS(无 smaps),只有 maps 级别的段/文件信息。
- 不提供 `top`(§7/§9);需要交互式总览请用卡上已有的 `htop`(其时钟显示同样受 §9 影响,亚秒刷新走 `select()` 大概率正常)。
- 二进制按设备内核 4.4.94 编 `LINUXV`;该宏只影响 `lsof -v` 显示,换内核不影响运行。
- 产物是 32 位 MIPS32r2(o32 ABI),只适用于 X1600 这类 MIPS32r2 目标。
- 卡上 `src/` 是 `--with-sources` 的**生成目录**(每次整理会整体重建),不要往里手放文件。