Skip to content

Instantly share code, notes, and snippets.

@G36maid
Created May 14, 2026 13:41
Show Gist options
  • Select an option

  • Save G36maid/dcf19e36c6596c5027ede7a9d576bced to your computer and use it in GitHub Desktop.

Select an option

Save G36maid/dcf19e36c6596c5027ede7a9d576bced to your computer and use it in GitHub Desktop.
FreeBSD Support Feasibility Analysis for minidump-writer (Issue #162)

FreeBSD 支援可行性分析報告

Issue: #162 — Please add support for FreeBSD 分析日期: 2026-05-14

一、總結

項目 評估
可行性 ✅ 可行 — FreeBSD 具備所有核心能力 (ptrace, procfs, process memory access)
工作量 🔶 中大型 — 約 15–25 工程師天 (僅 x86_64, 有 Linux 經驗)
主要風險 procfs 格式差異大、無 /proc/<pid>/task/、DSO debug 移植困難
好消息 FreeBSD 14+ 有 PT_COREDUMPnix crate 支援 FreeBSD ptrace

二、Issue 背景

Issue #162 要求為 minidump-writer crate 新增 FreeBSD 平台支援。

  • 來源: crash-handling#108 討論串
  • 影響: FreeBSD 版 Zed 編輯器 因此卡在 v0.198.6,無法升級(新版依賴不支援 FreeBSD 的 crash-handler crate)
  • 維護者態度: 願意 mentor、review 和 merge 貢獻,但無餘力自行實作
  • 關鍵線索: FreeBSD 有 ptrace() 與 Linux 相似,預期移植工作量不算太大

三、Linux 實作盤點 → 需移植的模組

src/linux/33 個檔案,依平台相依性分三類:

🔴 必須重寫(高度平台相依)

檔案 用途 Linux 特定 API FreeBSD 替代方案
process_reader.rs 讀取目標行程記憶體 process_vm_readv, /proc/pid/mem, PTRACE_PEEKDATA PT_IO (bulk read), /proc/pid/mem
maps_reader.rs 記憶體映射列舉 /proc/pid/maps + procfs-core crate kinfo_getvmmap()/proc/pid/map
minidump_writer/mod.rs 核心 writer 協調 ptrace::attach/cont/detach, waitpid(__WALL), SIGSTOP, /proc/pid/stat, /proc/pid/task/ PT_ATTACH/PT_CONTINUE/PT_DETACH, sysctl KERN_PROC_*
thread_info/*.rs 暫存器讀取 PTRACE_GETREGSET, PTRACE_GETREGS, NT_PRSTATUS PT_GETREGS, PT_GETFPREGS + struct reg
auxv/mod.rs + reader.rs ELF auxiliary vector /proc/pid/auxv + AT_SYSINFO_EHDR sysctl KERN_PROC_AUXV (無 vDSO)
dumper_cpu_info/x86.rs CPU 資訊 /proc/cpuinfo sysctl hw.model, hw.ncpu
minidump_writer/memory_info_list_stream.rs Memory info stream procfs_core::MemoryMaps kinfo_getvmmap() 轉換
minidump_writer/handle_data_stream.rs FD 列舉 /proc/pid/fd + readlink kinfo_getfiles()/proc/pid/fd
crash_context/x86_64.rs ucontext 轉換 REG_RIP, REG_RSP 等 glibc 常數 FreeBSD struct reg 欄位名不同 (r_rip, r_rsp)

🟡 需適應(中等改動)

檔案 原因
dso_debug.rs 讀取 r_debug/link_map — FreeBSD rtld 結構不同,可能需大幅改動或暫時省略
android.rs Android 專用,FreeBSD 不需要
maps_reader.rs 中的 vdso/linux-gate 處理 FreeBSD 沒有 vDSO

🟢 可直接複用

檔案 原因
module_reader.rs ELF 解析 (goblin) — FreeBSD 也是 ELF,完全通用
app_memory.rs 純資料結構
serializers.rs 序列化工具
minidump_writer/ 子 stream writers (多數) 呼叫 copy_from_process 的上層邏輯可重用

四、FreeBSD ↔ Linux API 對照表

ptrace

功能 Linux FreeBSD
附加 PTRACE_ATTACH PT_ATTACH
分離 PTRACE_DETACH PT_DETACH
繼續 PTRACE_CONT PT_CONTINUE
讀暫存器 PTRACE_GETREGSET + NT_PRSTATUS PT_GETREGS (直接取得 struct reg)
讀 FP 暫存器 PTRACE_GETREGSET + NT_PRFPREGSET PT_GETFPREGS
讀記憶體 (word) PTRACE_PEEKDATA PT_READ_D
讀記憶體 (bulk) process_vm_readv() PT_IO + PIOD_READ_D
核心傾印 N/A PT_COREDUMP (FreeBSD 14+) ✨
暫停執行緒 SIGSTOP + PTRACE_ATTACH PT_SUSPEND

亮點:FreeBSD 的 PT_IO 可一次讀取任意長度記憶體,比 Linux word-by-word PTRACE_PEEKDATA 高效得多。

procfs / 行程資訊

資訊 Linux FreeBSD
記憶體映射 /proc/pid/maps (6 欄位, 純文字) /proc/pid/map (10+ 欄位, 不同格式) 或 kinfo_getvmmap()
Thread 列舉 /proc/pid/task/ 目錄 — 需 sysctl KERN_PROC_THREADSlibprocstat
auxv /proc/pid/auxv (binary) sysctl KERN_PROC_AUXV/proc/pid/auxv
CPU 資訊 /proc/cpuinfo sysctl hw.model, hw.ncpu, hw.machine
記憶體讀取 /proc/pid/mem /proc/pid/mem
可執行路徑 /proc/pid/exe symlink /proc/pid/file symlink

x86_64 暫存器結構

// Linux struct user_regs_struct:
r15, r14, r13, r12, rbp, rbx, r11, r10,
r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax,
rip, eflags, rsp, cs, ss, ...

// FreeBSD struct reg:
r_r15, r_r14, r_r13, r_r12, r_rbp, r_rbx, r_r11, r_r10,
r_r9, r_r8, r_rax, r_rcx, r_rdx, r_rsi, r_rdi,
r_rflags, r_rip, r_rsp
// 注意: 無 orig_rax, 無 segment registers (cs, ss 等)

ELF Auxiliary Vector

常數 Linux FreeBSD 備註
AT_PHDR Program header 地址
AT_PHNUM Program header 數量
AT_ENTRY 進入點
AT_SYSINFO_EHDR FreeBSD 無 vDSO
AT_RANDOM FreeBSD 用不同機制
AT_BASE
AT_EXECPATH FreeBSD 特有
AT_NCPUS FreeBSD 特有

FreeBSD 也提供 elf_aux_info() 函式可直接查詢 auxv 值。


五、實作策略 — 兩條路線

路線 A:手動組裝(完整 minidump) ⭐ 推薦

仿照 Linux 模式,逐步實作每個子系統:

  1. ProcessReader — 用 PT_IO (PIOD_READ_D) 讀記憶體 + /proc/pid/mem 回退
  2. MapsReader — 用 kinfo_getvmmap() (sysctl wrapper) 取得映射
  3. ThreadInfosysctl KERN_PROC_THREADS 列舉 + PT_GETREGS/PT_GETFPREGS 取暫存器
  4. AuxvReadersysctl KERN_PROC_AUXV
  5. CpuInfosysctl hw.model, hw.ncpu
  6. CrashContext — FreeBSD ucontext_t → minidump RawContextCPU 映射
  7. DSO Debug — 初期可省略或簡化

優點:完整控制、可重用大部分 minidump stream writer、可測試每個子系統 缺點:工作量較大

路線 B:PT_COREDUMP + 轉換(FreeBSD 14+)

利用 FreeBSD 14+ 的 ptrace(PT_COREDUMP) 生成 core file,再用 minidump crate 解析轉換:

ptrace(PT_ATTACH, pid, NULL, 0);
waitpid(pid, &status, 0);

struct ptrace_coredump pc = {
    .pc_fd    = fd,        // 寫入的 file descriptor
    .pc_flags = 0,         // 或 PC_COMPRESS | PC_ALL
    .pc_limit = 0,         // 大小限制 (0 = 無限制)
};
ptrace(PT_COREDUMP, pid, &pc, sizeof(pc));

ptrace(PT_DETACH, pid, NULL, 0);

優點:kernel 幫你做完大部分工作 缺點:依賴 FreeBSD 14+、core→minidump 轉換需額外實作、控制粒度較粗


六、需要修改的共用檔案

檔案 改動
src/lib.rs cfg_if 加入 else if #[cfg(target_os = "freebsd")] { mod freebsd; pub use freebsd::*; }
src/module_reader.rs 加入 #[cfg(target_os = "freebsd")] re-export
src/process_reader.rs 加入 #[cfg(target_os = "freebsd")] re-export
Cargo.toml 加入 [target.'cfg(target_os = "freebsd")'.dependencies]
src/bin/test.rs 加入 FreeBSD 分支實作 test child commands
tests/freebsd_minidump_writer.rs 新增 — 複製 Linux 測試並調整

七、所需的新檔案

src/freebsd/
├── mod.rs                           # 模組根 + pub type Pid = i32
├── minidump_writer/
│   ├── mod.rs                       # MinidumpWriter + MinidumpWriterConfig
│   ├── errors.rs                    # WriterError 等
│   ├── thread_list_stream.rs        # (可複用 Linux 版)
│   ├── thread_names_stream.rs       # 需改用 sysctl 取 thread name
│   ├── systeminfo_stream.rs         # sysctl 取 CPU/OS 資訊
│   ├── memory_info_list_stream.rs   # kinfo_getvmmap 轉換
│   ├── mappings.rs                  # (可複用大部分)
│   ├── exception_stream.rs          # (可複用大部分)
│   ├── handle_data_stream.rs        # kinfo_getfiles 或 /proc/pid/fd
│   ├── app_memory.rs                # (可複用)
│   └── memory_list_stream.rs        # (可複用)
├── process_reader.rs                # PT_IO + /proc/pid/mem
├── maps_reader.rs                   # kinfo_getvmmap() 或 /proc/pid/map
├── thread_info/
│   ├── mod.rs                       # FreeBSD thread 列舉 + 暫存器讀取
│   └── x86.rs                       # struct reg → RawContextCPU
├── module_reader.rs                 # (可複用 Linux 版或直接 re-export)
├── auxv.rs                          # sysctl KERN_PROC_AUXV
├── crash_context/
│   ├── mod.rs
│   └── x86_64.rs                    # FreeBSD ucontext_t 映射
├── dumper_cpu_info.rs               # sysctl hw.model, hw.ncpu
├── dso_debug.rs                     # 初期可省略
├── app_memory.rs                    # (可複用)
└── serializers.rs                   # (可複用)

八、風險與注意事項

風險 嚴重度 說明
procfs-core crate 不支援 FreeBSD 🔴 高 需要替代方案 (kinfo_getvmmap 等),或自己寫 /proc/pid/map parser
nix 缺少 PT_IO/PT_COREDUMP 綁定 🟡 中 需直接用 libc::ptrace() 或貢獻上游
DSO debug (r_debug/link_map) 🟡 中 FreeBSD rtld 結構不同,初期可省略此 stream
Thread 列舉無 procfs 🟡 中 需透過 sysctllibprocstat
CI 測試環境 🟡 中 需 FreeBSD runner 或 QEMU
FreeBSD 14+ 限定功能 🟢 低 PT_COREDUMP 是額外選項,不阻塞基本功能

九、參考資源

FreeBSD API 文件

  • ptrace(2) — PT_ATTACH, PT_IO, PT_GETREGS, PT_COREDUMP
  • kinfo_getvmmap(3) — 記憶體映射
  • kinfo_getproc(3) — 行程資訊
  • sysctl(3) — KERN_PROC_* MIBs
  • procfs(5) — /proc 佈局

現有專案參考

  • Breakpad: 無 BSD 支援,但有完整的 Linux 實作可參考 (src/client/linux/minidump_writer/)
  • Crashpad: 無 BSD 支援
  • nix crate: src/sys/ptrace/bsd.rs — FreeBSD ptrace 綁定(缺少 PT_IO/PT_COREDUMP)

上游討論


十、結論

FreeBSD 支援完全可行。核心 ptrace 機制相似,且 FreeBSD 的 PT_IO 在記憶體讀取上比 Linux 更優雅。主要工作量在於:

  1. 替換 procfs 依賴procfs-core crate 無法在 FreeBSD 使用,需改用 kinfo_getvmmap() + sysctl
  2. 重寫 thread 列舉 — 沒有 /proc/pid/task/,需 sysctl
  3. 適應暫存器結構 — 欄位名不同但語義相同
  4. 新增 Cargo 目標 — FreeBSD 條件依賴

建議從 路線 A (手動組裝) 開始,先實作 x86_64 架構,驗證基本 minidump 生成後再擴展。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment