有没有办法获取当前运行的 Linux 内核支持的系统调用的数量或列表?所以我想找到一种方法来“读取”正在运行的内核的系统调用表。
答案1
该文件/proc/kallsyms
列出了正在运行的内核的所有符号。按照惯例,系统调用的名称以 开头sys_
。在 64 位系统上,32 位程序的系统调用的名称以sys32_
.严格来说,这列出了内部内核函数,而不是系统调用,但我认为对应关系确实有效(每个系统调用都会调用内部内核函数来完成这项工作,并且我认为该名称始终是带有sys_
前缀的系统调用的名称)。
</proc/kallsyms sed -n 's/.* sys_//p'
这通常不是有用的信息,因为系统调用变化非常缓慢。可选组件提供现有系统调用方面的功能,使用设备等通用功能(带有读写控制确定支持的系统调用列表不会告诉您有关系统支持的功能的任何read
信息。write
其他内部函数名称也无济于事,因为它们变化得非常快:在一个内核版本上实现某些功能的函数名称可能会在下一版本上发生变化。
答案2
长话短说
在撰写此答案时,我不断寻找新的替代方案,因此我只是写了有关每个替代方案的一些详细信息,并做了一些统计数据。基本上,您可以:
- 阅读 Gilles 的答案,它提供了一种干净、快速的方法(依赖于
/proc
)。 - 使用文档资源。
- 使用系统的 C 头文件。
- 使用内核源代码本身。
- 使用
/sys
目录。
进行数学计算后,我建议(在我的替代方案中)使用/sys
文件系统,因为它似乎在系统调用数量方面给出了最佳结果。如果您不想阅读其他技巧,可以直接跳到该部分。
使用文档资源
虽然您可能会错过其中一些,但您可以使用apropos
列出属于第 2 部分(系统调用)的所有联机帮助页:
$ apropos -s2 . | awk '{print $1}' | column
column
如果您不想要花哨的列式输出,请将其删除。
我刚刚发现,但是有一个关于系统调用的 Linux 手册页,你可以在其中找到其中的大部分内容。
$ man syscalls
我还发现了这两个可能很有趣的网站:
使用头文件
编辑 :现在,当涉及到以编程方式(或者至少不依赖记录的功能)确定哪些系统调用可用时,恐怕内核不会保留其系统调用表,至少不会以列表的形式保存字符串(正如您可能期望操纵它们一样)。在这个级别,我们更多地讨论函数地址和指针,而不是函数名称。
我刚刚浏览了我的/usr/include
目录并grep
添加了一些内容:您可能会发现以下目录很有趣。其中一些在您的计算机上可能会有所不同,具体取决于您的体系结构和发行版,但我相信您能够适应它们。
- /usr/include/linux
- /usr/include/x86_64-linux-gnu
- /usr/include/系统
- /usr/include/asm-generic
通过在此文件中查找函数定义,您将遇到许多系统调用,即使它们并未在其中完全定义。我在这些目录中运行了一些grep
,并且能够找到一些系统调用的提及。这是一个例子:
$ grep 'sys_exit' /usr/include -R
asm-generic/unistd.h:__SYSCALL(__NR_exit, sys_exit)
所以,我猜找到其中一些的另一种方法是:
$ egrep '^__SYSCALL' /usr/include -Rh | awk '{print $2}' | tr -d ')'
使用内核的源代码及其系统调用表
另一个解决方案是使用内核源代码本身(而不仅仅是标头!),并找到一种有效搜索它的方法。自内核提交 303395ac3bf3e2cb488435537d416bc840438fcb,您可能会发现这比以前容易一些。这是 3.13 的示例(这是我的内核):
$ wget https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/plain/arch/x86/syscalls/syscall_64.tbl?id=refs/tags/v3.13 -O syscall_64.tbl
现在您已经获得了实际的系统调用表,只需浏览它即可:
$ while read line; do awk '! /#/ {print $3}'; done < syscall_64.tbl
您可以找到一种方法,使用和uname
直接从arch
tbl
git.kernel.org,基于您运行的内核版本和体系结构。
使用/sys
文件系统
Gilles的回答给了我一点启发,你可能会在里面找到那些系统调用/sys/kernel/debug/tracing/events/syscalls
。该目录用于监控系统上各个系统调用的使用情况。每个系统调用都有两个目录:
- sys_enter_[系统调用]
- sys_exit_[系统调用]
因此,使用ls
,grep
和cut
...
$ ls /sys/kernel/debug/tracing/events/syscalls | grep 'sys_enter' | cut -d'_' -f3
统计数据
在我的系统上:
- 使用手册页发现了 440 个系统调用。
grep
-ing for__SYSCALL
在头文件中显示了 212 个系统调用。- 从内核源读取系统调用表发现有 346 个系统调用。
- 使用
/sys
显示的 290 系统调用。
现在,如果我把所有东西放在一起......
$ apropos -s2 . | awk '{print $1}' > system_calls.txt
$ egrep '^__SYSCALL' /usr/include -Rh | awk '{print $2}' | tr -d ')' >> system_calls.txt
$ while read line; do awk '! /#/ {print $3}'; done < syscall_64.tbl >> system_calls.txt
$ ls /sys/kernel/debug/tracing/events/syscalls | grep 'sys_enter' | cut -d'_' -f3 >> system_calls.txt
$ sort < system_calls.txt | uniq | wc -l
707
好了,707 系统调用!当然,这个数字反映了“系统调用”的非常灵活的定义,因为3.13 应该只提供 274 个系统调用(阅读/sys
似乎是最接近的解决方案)。
答案3
所有的答案都很好。
如果您正在寻找特定的系统调用名称:
$ cat /proc/kallsyms | grep <sys_call_name>
如果您正在寻找所有系统调用的列表:
$ cat /proc/kallsyms