Linux系统调用查询与跟踪

149 阅读4分钟

本文来源于大佬的一道面试题:如何查询Linux接口调用次数

虽然最终发现对该面试题的理解有着微妙的偏差,不过如果把Linux接口调用次数理解为程序对Linux的系统调用次数,这其实是一个很有意思的问题。


系统调用数量的意义

所谓的系统调用是指程序进入内核执行任务的方式。程序利用系统调用进行一系列操作,如:进程管理、网络交互、文件读写等等。绝大部分时候应用程序指只需include相关的头文件,即可像调用一个API一样进行系统调用,虽然如此。Linux内核的系统调用基础架构相当复杂,也存在着各有优缺点其他调用方式。

常见的程序的调用可以分为两大类,一类是系统调,用另一类自身函数的调用。因此系统调用是程序流程的重要组成部分;除此之外,系统调用的数量还与系统中断数量等息息相关。因此,获取程序系统调用的情况对于排查及定位程序的异常或者对程序进行性能的分析都有着重要意义。

如何跟踪进程的系统调用

Linux是通过进行系统调用来跟踪其他系统调用的,这个系统调用就是ptrace,它可以暂停被跟踪进程,检查和设置寄存器和内存,查看和修改被追踪进程的内存和寄存器。

大部分的linux系统调用都设计得非常简洁,ptrace也是如此,其所具备的功能相对简单。当需求比较独特时,我们可以自己编写程序调用ptrace来跟踪其他程序的系统调用。但这无疑是一个非常麻烦的事情,因此绝大部分时候我们会使用一些基于ptrace的工具,比如GDB,strace等,本文将会对strace进行简要的介绍。

strace 简介

strace是一个大部分linux发行版自带的系统工具。通常用来跟踪进程执行时的系统调用和所接收的信号。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

相关参数如下所示:

# 例1:启动并跟踪一个程序  
strace -f -F -o ~/straceout myserver  
  
# 例2:跟踪已经启动的进程(这里选取了一个uwsgi进程)  
strace -p 38128  
Process 38128 attached - interrupt to quit  
wait4(-1, 0x7ffcf5eb2b5c, WNOHANG, NULL) = 0  
epoll_wait(30, {}, 1, 1000) = 0  
lseek(2, 0, SEEK_CUR) = 108272503  
getsockopt(6, SOL_TCP, TCP_INFO, "\n\0\0\0\0\0\0\0@B\17\0\0\0\0\0\30\2\0\0\0\0\0\0\0\0\0\0d\0\0\0"..., [104]) = 0  
wait4(-1, 0x7ffcf5eb2b5c, WNOHANG, NULL) = 0  
epoll_wait(30, {}, 1, 1000) = 0  
lseek(2, 0, SEEK_CUR) = 108272503  
getsockopt(6, SOL_TCP, TCP_INFO, "\n\0\0\0\0\0\0\0@B\17\0\0\0\0\0\30\2\0\0\0\0\0\0\0\0\0\0d\0\0\0"..., [104]) = 0  
  
# 例3:追踪进程和线程  
$ strace -fp [pid]  
  
# 例4:追踪进程和限定字符  
$ strace -s 80 -fp [pid]  
  
# 例5:统计进程的调用情况  
$strace -c -f -p [pid] -o [file_name]  
  
% time seconds usecs/call calls errors syscall  
------ ----------- ----------- --------- --------- ----------------  
60.47 19.181735 7429 2582 1258 futex  
23.42 7.429387 212268 35 35 restart_syscall  
11.14 3.533856 983 3596 epoll_wait  
1.50 0.475396 51 9368 setsockopt  
0.79 0.250978 54 4684 fcntl  
0.72 0.227007 48 4684 2342 epoll_ctl  
0.42 0.132211 56 2342 2342 connect  
0.40 0.127517 54 2342 getsockopt  
0.39 0.123448 53 2342 close  
0.38 0.119249 51 2342 dup2  
0.37 0.117744 50 2342 socket  
0.00 0.000432 15 29 recvfrom  
0.00 0.000210 7 29 poll  
0.00 0.000000 0 10 write  
0.00 0.000000 0 29 sendto  
------ ----------- ----------- --------- --------- ----------------  
100.00 31.719170 36756 5977 total

小结

回到文章开头的问题,我们可以给出答案:通过strace这一工具,我们不仅可以轻易的获取指定进程的系统调用,也有方便的方法并对一段时间内的状态进行统计。剩下的就只是监控范围的问题了。如果需要长时间的监控系统调用并形成日志,也可以考虑使用Linux的用户空间审计工具audit来实现类似的效果。