0%

使用strace监控系统调用

strace用来获取系统调用的参数和返回值,无论程序是以什么样的方式编译。被跟踪的程序可以是从strace命令运行的,也可以是系统上已经运行的进程,这需要适当的权限。程序无需重新编译,可以直接使用strace调试。可谓是调试工具中的一把瑞士军刀。

strace安装

根据自己的Linux发现版本,选择相应的命令安装即可。也可以从strace仓库下载release包,编译安装。

1
2
yum -y install strace   # centos
apt-get install strace # ubuntu

strace基本使用方法

strace的使用方法非常简单,只需加上要跟踪的程序名即可。假如要查看pwd程序发出的系统调用,只需执行指令strace pwd即可,输出如下面所示(进行了删减)。每一行表示一个系统调用,每一行由等号分割为两部分。等号左边是系统调用及其对应的参数,等号右边是系统调用的返回值。如果系统调用出错,还会显示对应的errno

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# strace pwd
execve("/usr/bin/pwd", ["pwd"], 0x7ffd6a32df00 /* 32 vars */) = 0
brk(NULL) = 0x14fd000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7bc2fd5000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
......
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106176928, ...}) = 0
mmap(NULL, 106176928, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7bbc4a4000
close(3) = 0
getcwd("/root", 4096) = 6
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7bc2fd4000
write(1, "/root\n", 6/root
) = 6
close(1) = 0
munmap(0x7f7bc2fd4000, 4096) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++

高级strace参数

参数 描述
-c 统计每个系统调用的时间、调用和错误
-d 显示strace的一些调试输出
-e 指定输出的过滤表达式
-f 在创建子进程的时候跟踪它们
-ff 如果写入到输出文件,则把每个子进程写入到单独的文件中
-i 显示执行系统调用时的指令指针
-o 把输出写入到指定文件
-p 附加到由PID指定的现有进程
-q 抑制关于附加和分离的消息
-r 对每个系统调用显示一个相对的时间戳
-t 把时间添加到每一行
-tt 把时间添加到每一行,包括微秒
-ttt 添加epoch形式的时间(从1970年1月1日开始的秒数),包括微秒
-T 显示每个系统调用花费的时间
-v 显示不经省略的系统调用信息
-x 以十六进制格式显示所有非ASCII字符
-xx 以十六进程格式显示所有字符串
-s 字符串的长度,超过的字符串会显示为...

其中-e参数非常有用,可以过滤指定的系统调用。常见用法如下。更多用法请参考man手册

选项 说明
-e trace=read,getpid 只跟踪指定的系统调用
-e trace=!read 不跟踪read系统调用
-e trace=network 跟踪网络相关的系统调用
-e trace=signal 跟踪信号相关的系统调用
-e trace=ipc 跟踪IPC相关的系统调用

-p参数附加到现在正在运行的程序,对调试后台程序非常有用。当然,这需要相应的权限。

strace工作原理

使用ptrace()系统调用,可以在子进程调用系统调用时暂停子进程,这时可以读取子进程相关寄存器的值,从而确定子进程调用的系统调用和相关参数。

相关资料: