linux内核新增系统调用不会自动被strace或man识别,必须手动更新其系统调用表;需在syscall_64.tbl等文件中注册唯一编号和入口函数,并在syscalls.h中声明原型,否则strace仅显示syscall_442等数字而非函数名,glibc也不提供封装,需用syscall(442,...)手动调用并配合strace -e trace=442验证。

Linux内核新增系统调用不会自动出现在man syscalls或strace -e trace=all的默认列表里,必须查源码或编译产物才能确认——因为系统调用号和函数名是硬编码在内核源码中的,用户空间工具(包括strace、perf)只有在更新自身定义表后才能识别新调用。
查 syscall_64.tbl 或 syscall_32.tbl 文件
这是最直接的方式。新增系统调用必然要注册到对应架构的系统调用表中,路径固定:
-
/usr/src/linux/arch/x86/entry/syscalls/syscall_64.tbl(x86_64) -
/usr/src/linux/arch/x86/entry/syscalls/syscall_32.tbl(i386) - 若使用其他架构(如 arm64),路径为
/arch/arm64/entry/syscalls/syscall.tbl
每行格式为:编号 架构 abi 名称 入口函数,例如:
442 64 common my_new_syscall __x64_sys_my_new_syscall
注意:编号必须唯一且未被占用;abi列标示适用 ABI(如common表示通用,64仅限 x86_64);入口函数名需与syscalls.h中声明一致。
看 include/linux/syscalls.h 是否有新声明
系统调用函数原型必须在此头文件中用asmlinkage long sys_XXX或asmlinkage long __sys_XXX形式声明,否则链接阶段会失败。例如:
asmlinkage long sys_my_new_syscall(int arg1, const char __user *arg2);
常见错误是只改了syscall_*.tbl但漏加这行声明,导致make报undefined reference to `sys_my_new_syscall'。
另外,如果调用带__user指针参数,必须配套实现copy_from_user等安全检查逻辑,否则运行时触发-EFAULT或 panic。
确认 strace 和 libc 是否已支持该调用
即使内核已导出新系统调用,用户空间工具仍可能不认识它:
-
strace输出中看到的是数字(如syscall_442(0x7fff1234))而非函数名,说明其内置的系统调用名映射表未更新 -
glibc不提供对应封装函数(如my_new_syscall()),你只能用syscall(442, ...)手动调用 - 更新
strace需重新编译,从其源码的linux/x86_64/syscallent.h等文件注入新条目
临时验证可用:echo 'syscall(442)' | gcc -x c - -o test && ./test,再用strace ./test观察是否能捕获到原始编号调用。
运行时检查 /proc/sys/kernel/syscall_table(不可靠)
某些内核版本(如带 debugfs 支持)可通过debugfs暴露系统调用表,但标准发行版几乎都不启用。更现实的做法是:
- 用
grep -r "my_new_syscall" /usr/src/linux/确认所有关联文件(.tbl、.h、.c)均已修改 - 编译后执行
cat /proc/kallsyms | grep my_new_syscall,看到符号存在说明已加载 - 写一个最小测试程序调用
syscall(442, ...),配合strace -e trace=442验证是否触发
最容易被忽略的一点:新系统调用在不同内核版本间编号可能冲突,跨版本移植时务必比对syscall_*.tbl全量内容,不能只看最后一行。











