Linux kernel 在Linux系统调用中,系统调用完成后(在sys_出口跟踪点),系统调用参数是否保留在寄存器中?

Linux kernel 在Linux系统调用中,系统调用完成后(在sys_出口跟踪点),系统调用参数是否保留在寄存器中?,linux-kernel,system-calls,tracepoint,Linux Kernel,System Calls,Tracepoint,是否保证能够读取sys\u exittracepoint处的所有syscall参数 是使用内核静态跟踪点捕获系统调用的内核模块。在这个项目中,一些系统调用参数是在sys\u entertracepoint读取的,一些其他参数是在sys\u exit读取的(当然是返回值,用户空间中的内容是为了避免pagefault) 为什么不在系统退出时读取所有参数?这是因为某些参数可能在系统退出时不可用吗 是否保证能够读取sys\u exittracepoint处的所有syscall参数 是的。。。不,我们需要

是否保证能够读取
sys\u exit
tracepoint处的所有syscall参数

是使用内核静态跟踪点捕获系统调用的内核模块。在这个项目中,一些系统调用参数是在
sys\u enter
tracepoint读取的,一些其他参数是在
sys\u exit
读取的(当然是返回值,用户空间中的内容是为了避免pagefault)

为什么不在系统退出时读取所有参数?这是因为某些参数可能在系统退出时不可用吗

是否保证能够读取
sys\u exit
tracepoint处的所有syscall参数

是的。。。不,我们需要区分参数和寄存器。Linux系统调用应保留所有通用用户空间寄存器,但用于返回值的寄存器除外(在某些体系结构上,还应保留第二个寄存器以指示是否发生错误)。然而,这并不意味着系统调用的输入参数不能在入口和出口之间更改:如果寄存器持有指向某些数据的指针的值,而寄存器本身没有更改,那么它指向的数据很可能会更改

查看静态跟踪点
sys\u exit
,可以看到只跟踪syscall号码(
id
)及其返回值(
ret
)。更多信息,请参见我答案底部的注释

为什么不在系统退出时读取所有参数?这是因为某些参数在系统退出时不可用吗

是的,我想说的是,确保跟踪参数的正确性是为什么仅在出口处跟踪是个坏主意的主要原因。即使获得寄存器的值,也无法知道syscall出口处的实际参数。即使系统调用本身保证保存和恢复用户寄存器的状态,系统调用本身也可以更改作为参数传递的数据。例如,
recvmsg
syscall获取指向内存中的
struct msghdr
的指针,该指针用作输入和输出参数;
poll
syscall对指向
struct pollfd
的指针执行相同的操作。此外,另一个线程或程序在进行系统调用时可以很好地修改程序的内存,从而改变数据

在特定情况下,系统调用在返回之前也可能需要很长时间(例如,在终端上执行
睡眠
,或阻塞
读取
,在侦听套接字上执行
接受
,等等)。如果您只在出口处跟踪,您将获得非常不正确的计时信息,最重要的是,您必须等待很长时间才能捕获任何有意义的信息,即使该信息在入口点已经可用


关于
系统退出的注意事项
跟踪点

虽然您可以精确地提取当前任务保存的寄存器的值,但我不能完全确定在
sys\u exit
tracepoint中这样做的语义。我搜索了一些关于这个特定案例的文档,但没有找到,内核代码很好。。。复杂的

到达出口挂钩的调用链应为:

  • 特定于Arch的入口点(例如,对于x86
    int 0x80
    • 特定于Arch的条目处理程序(例如,对于x86
      int 0x80

如果在系统调用期间向进程发送致命信号,而实际进程永远不会到达系统调用的出口(即,没有任何值返回到用户空间),则跟踪点仍将被命中。当发生此类信号传递时,将使用特殊的内部返回值,如
-ERESTARTSYS
()。这个值不是实际的syscall返回值(它不会返回到用户空间),而是只供内核使用。因此,如果进程接收到致命信号,则系统出口跟踪点似乎被特殊的ERESTARTSYS击中。例如,在
SIGSTOP
+
SIGCONT
的情况下,不会发生这种情况。不过,请恕我直言,因为我找不到合适的文档。

谢谢您的回答。我基本上理解这背后的原因。但有一件事我想确认,我尝试了您提到的示例,即使用无效缓冲区发出
read
,但返回值
EFAULT
到达
sys\u exit
。是否有其他示例表明系统调用可能被终止,并且无法到达
sys\u exit
?再次感谢@user2828102是的,你是对的,这可能不是最好的例子,我忘记了
read
检查参数,如果缓冲区指针无效,它会返回
EFAULT
,而不会终止进程。在任何情况下,如果您在一个终端中运行
strace-f cat
(它将阻止等待
读取
),然后打开另一个终端并发出
ps aux | grep cat
来查找
cat
进程的PID,然后
kill-9 PID
来终止它,您都可以很容易地测试这一点。虽然strace显示一个“?”作为
read
返回值,但我编写了一个演示LKM,在
sys\u exit
跟踪点打印一条消息,结果显示
read
仍然到达
sys\u exit
返回代码
-512
意味着
ERESTARTSYS
@user2828102是的,对不起,我删除了那部分,检查我编辑的答案。