系统调用追踪工具strace

简介:

当我们想知道某个进程为什么突然卡了,或者是某个工具到底是如何实现的时候。strace就派上了用场。它能将程序的调用信息打印出来。

strace原理:

它的实现基础是ptrace系统调用。ptrace系统调用提供了一种方法来跟踪和控制进程的执行,它可以读取和修改进程地址空间中的内容,包括寄存器的值。ptrace主要用于实现断点调试和跟踪系统调用。

ptrace系统调用

1 #include <sys/ptrace.h>
2 int ptrace(int request, int pid, int addr, int data);

Ptrace 提供了一种父进程可以控制子进程运行,并可以检查和改变它的核心image。它主要用于实现断点调试。

一个被跟踪的进程运行中,在执行系统调用之前,内核会先检查当前进程是否处于被“跟踪”(traced)的状态。如果是的话,内核暂停当前进程并将控制权交给跟踪进程,使跟踪进程得以察看或者修改被跟踪进程的寄存器

在一个进程被跟踪之后,跟踪者进程会在某种意义上充当被跟踪进程的父进程(如使用ps命令就可以看到他们的父子关系),而子进程真正的父进程被保存在其task_struct结构的real_parent成员中。

当子进程产生系统调用时,就会被暂停,父进程会在每次调用wait()时得到子进程停止运行的通知,这时父进程就可以检测和修改子进程了,随后父进程可以让子进程继续运行。当父进程不想跟踪了,可以通过设置PTRACE_KILL标记来终止子进程的运行。也可以通过设置PTRACE_DETACH标记让子进程解除被跟踪,继续正常运行。
函数参数:

  1. request:用于选择一个操作。
  2. pid:目标进程即被跟踪进程的pid。
  3. addr用于修改和拷贝被跟踪进程的进程地址空间的数据。
  4. data功能同addr。

父进程跟踪一个进程的方式有两种:

  1. 调用fork(),然后子进程打上PTRACE_TRACEME标记,并执行exec。
  2. 父进程可以给自己打上PTRACE_ATTACH标记来跟踪一个已有进程。

所以我们看strace有两种用法,一个是strace直接加要运行的程序,一个是用-p指定一个正在运行的进程。

一个进程被跟踪后,他只要接收到一个信号(即使这个信号被设置为忽略)就会停止运行(SIGKILL除外),然后父进程会在每次调用wait()时得到子进程停止运行的通知,这时父进程就可以检测和修改子进程了,随后父进程可以让子进程继续运行。

当父进程不想跟踪了,可以通过设置PTRACE_KILL标记来终止子进程的运行。也可以通过设置PTRACE_DETACH标记让子进程解除被跟踪,继续正常运行。

strace用法:

最简单的用法其实就是trace后面直接跟着要执行的命令。比如:

1 strace ls -l

就能追踪到它的系统调用。

1 execve("/bin/ls", ["ls""-l"], [/* 22 vars */]) = 0
2 brk(0)                                  = 0x2073000
3 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fee98686000
4 access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
5 open("/etc/ld.so.cache", O_RDONLY)      = 3
6 .........

命令参数:

  • -p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。
  • -e 函数名:只追踪定义函数名。
  • -f :除了跟踪当前进程外,还跟踪其子进程。
  • -o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。

在linux中,很多性能查看命令都是通过读取/proc中的文件实现的。所以我们如果想学习它们的实现,就可以使用strace追踪,用-e筛选出open函数,就知道它读取了什么文件。比如mount命令。

01 strace -eopen mount
02 open("/etc/ld.so.cache", O_RDONLY)      = 3
03 open("/lib64/libblkid.so.1", O_RDONLY)  = 3
04 open("/lib64/libuuid.so.1", O_RDONLY)   = 3
05 open("/lib64/libselinux.so.1", O_RDONLY) = 3
06 open("/lib64/libsepol.so.1", O_RDONLY)  = 3
07 open("/lib64/libc.so.6", O_RDONLY)      = 3
08 open("/lib64/libdl.so.2", O_RDONLY)     = 3
09 open("/proc/filesystems", O_RDONLY)     = 3
10 open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
11 open("/dev/null", O_RDWR)               = 3
12 <span style="color: #ff0000;"><strong>open("/etc/mtab", O_RDONLY)             = 3
13 </strong></span>

参考资料:

http://blog.csdn.net/sealyao/article/details/6710772

转载请注明:旅途@KryptosX » 系统调用追踪工具strace

目录
相关文章
|
8月前
|
Python
Python 高级编程与实战:深入理解面向对象与并发编程
本文深入探讨Python的高级特性,涵盖面向对象编程(继承、多态、特殊方法、类与实例属性)、异常处理(try-except、finally)和并发编程(多线程、多进程、异步编程)。通过实战项目如聊天服务器和异步文件下载器,帮助读者掌握这些技术,编写更复杂高效的Python程序。
|
NoSQL Java API
MongoDB 强制使用索引 hint
MongoDB 强制使用索引 hint
504 3
|
存储 前端开发 中间件
vue3之vite配置vite-plugin-mock使用mock轻松创建模拟数据提高开发效率
vue3之vite配置vite-plugin-mock使用mock轻松创建模拟数据提高开发效率
1762 0
|
存储 SQL JSON
两万字详解MongoDB从入门到精通(一)
两万字详解MongoDB从入门到精通
1521 1
|
前端开发 Java 编译器
Android HAL深入探索(7)hidl-gen和hidl2aidl的使用详解
Android HAL深入探索(7)hidl-gen和hidl2aidl的使用详解
2542 0
|
Unix Linux Python
Python---多进程与多线程笔记
1.多进程与多线程介绍 / 区别 现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢? 答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。
3555 0
|
存储 安全 Ubuntu
Linux kernel 内核升级与降级实战
Linux kernel 内核升级与降级实战
934 0
|
安全 前端开发 应用服务中间件