运行内核时支持的系统调用


9

有没有办法获取当前正在运行的Linux内核支持的系统调用的数量或列表?因此,我想找到一种“读取”正在运行的内核的syscall表的方法。

Answers:


15

该文件/proc/kallsyms列出了正在运行的内核的所有符号。按照惯例,系统调用的名称以开头sys_。在64位系统上,对32位程序的系统调用的名称以开头sys32_。严格来说,它列出了内部内核函数,而不是系统调用,但是我认为通信确实有效(每个系统调用都会调用内部内核函数来完成这项工作,而且我认为名称始终是带有sys_前缀的系统调用的名称。)。

</proc/kallsyms sed -n 's/.* sys_//p'

这通常不是有用的信息,因为系统调用的变化非常缓慢。可选组件使用设备(使用ioctl何时readwrite不剪切时使用ioctl),文件系统,套接字等常规功能来提供现有系统调用的功能。确定受支持的syscall列表不会告诉您有关这些功能的任何信息系统支持的功能。其他内部函数名称也无济于事,因为它们的变化非常快:在一个内核版本上实现某些功能的函数的名称可能在下一版本上更改。


+1。这就是我说“我要让比我有更多经验的人回答你”的意思。另外,由于/proc/kallsyms可以像其他文件一样进行操作,因此在程序中使用它变得非常容易。
约翰·史密斯

2
@JohnWHSmith“可以像其他任何文件一样进行操作”…警告:在带有内核ASLR的系统上,该文件只能由root读取。
吉尔(Gilles)'所以

7

TL; DR

在写这个答案时,我一直在寻找新的选择,所以我只写了一些关于每个选择的详细信息,并做了一些统计。基本上,您可以:

  • 阅读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 / sys
  • / 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 ')'

使用内核的源代码及其syscall表

另一种解决方案是使用内核源代码本身(而不只是标头!),并找到一种有效搜索它的方法。由于内核提交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

现在您已经获得了实际的syscalls表,只需浏览即可:

$ while read line; do awk '! /#/ {print $3}'; done < syscall_64.tbl

您可以找到一种方法,使用uname和,根据运行的内核版本和体系结构直接从git.kernel.orgarch下载tbl文件。

使用/sys文件系统

Gilles的回答给了我一些启发,您可能会在其中找到这些系统调用/sys/kernel/debug/tracing/events/syscalls。该目录用于监视系统上每个系统调用的使用。每个系统调用中都有两个目录:

  • sys_enter_ [syscall]
  • sys_exit_ [syscall]

因此,使用lsgrepcut...

$ ls /sys/kernel/debug/tracing/events/syscalls | grep 'sys_enter' | cut -d'_' -f3

统计资料

在我的系统上:

  • 使用手册页显示了440个系统调用。
  • grep__SYSCALL头文件中的-ing 显示212个系统调用。
  • 从内核源代码读取syscalls表显示了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似乎是最接近的解决方案)。


我正在寻找一种以某种方式“读取”系统调用表的方法,而不是找出手册页中记录了哪些系统调用
Swair,2014年

我不认为内核会保留其系统调用列表,至少不会保留为字符串列表。我编辑了答案。如果有实际的方法,我会让比我有更多经验的人回答你;)
约翰·W·史密斯

因此,我在向内核添加系统调用并尝试使用它时给出了“未实现的功能”,对此我感到疑惑,并且我想知道是否有某种方法可以获取当前内核的syscall表。当我执行“ #make install”时,更新grub并启动新内核,新内核在哪一步得到包含新系统调用的相关包含文件?
14

1
如果找不到系统调用,则说明您未正确实现它。我的答案告诉您如何找到Linux的系统调用,而不告诉您如何调试自己的系统调用(因为这不是您要的内容)。如果您在开发它时遇到问题,则应专门询问一个问题,并避免XY问题
约翰·史密斯

@swair通过添加系统调用来添加功能是非常不寻常的。由于您未提供任何代码,因此我们无法确定到底出了什么问题(并且,如果您的问题需要C代码,那么这里就没问题了,但您可以在Stack Overflow上找到它)。我怀疑您实现了系统调用(是否正确),并且正试图通过C程序使用它,并且您缺少编写用于进行系统调用的C函数的步骤。系统调用不是普通的函数调用。
吉尔斯(Gilles)'所以

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.