You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何dtruss未记录二进制程序的stdout写入系统调用?如何解决?

问题背景

我熟悉Linux下的strace,刚接触macOS的dtruss,写了如下Hello World程序:

#include <stdio.h>

int main(){
  printf("hello world\n");
}

在Linux上用strace ./HelloWorld运行时,能看到包含write系统调用的输出:

strace ./HelloWorld
...
write(1, "hello world\n", 12hello world
)           = 12

但在macOS上执行sudo dtruss -f ./Hello时,却看不到任何系统调用输出:

sudo dtruss -f   ./Hello
Password:
dtrace: system integrity protection is on, some features will not be available

        PID/THRD  SYSCALL(args)                  = return
hello world

想知道:

  1. 为什么看不到write系统调用?
  2. 如何调整dtruss的调用方式来显示系统调用?
  3. 我原本以为系统完整性保护(SIP)仅适用于系统二进制文件,能否解释SIP对用户程序的限制依据?

解答

1. 看不到write系统调用的原因

  • libc实现差异:macOS的libc对printf的优化逻辑和Linux不同,它不会直接调用write系统调用,而是使用write_nocancel、writev这类带前缀的系统调用变体;另外stdio的缓冲机制可能导致输出缓冲未在进程运行时刷新,系统调用延迟到进程退出后才执行,而dtruss默认不会追踪这一阶段的调用。
  • SIP功能限制:开启SIP后,dtruss依赖的dtrace会被限制部分特权功能,即使是用户自行编译的程序,也无法完整追踪所有系统调用,部分探针会被禁用。

2. 调整dtruss调用方式的方法

  • 指定追踪目标系统调用:直接指定要追踪的系统调用(包括变体),覆盖默认追踪列表,命令示例:
    sudo dtruss -f -t write,write_nocancel,writev ./Hello
    
  • 强制触发缓冲刷新:修改程序,在printf后添加fflush(stdout);,或者运行时将输出重定向到文件(触发缓冲强制刷新):
    sudo dtruss -f ./Hello > out.txt
    
  • 临时关闭SIP(仅测试用,不推荐):如果需要完整的dtrace功能,可以重启Mac进入恢复模式,执行csrutil disable关闭SIP,测试完成后再执行csrutil enable重新开启。

3. SIP对用户程序的限制依据

SIP的设计目标是保护整个系统的完整性,并非仅针对系统二进制文件。开启SIP后,dtrace会受到以下限制:

  • 禁止追踪系统进程和受保护的内核组件;
  • 限制对用户进程的部分探针类型,比如无法使用pid provider的部分功能追踪用户级函数调用;
  • 即使是用户自行编译的程序,dtrace也无法绕过SIP限制获取完整的系统调用追踪数据,因为SIP会阻止dtrace加载必要的内核模块或执行特权级追踪操作。

内容的提问来源于stack exchange,提问作者merlin2011

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:13:26