程序中的系统调用工具(二十五):跟踪系统
优采云 发布时间: 2021-08-02 00:28程序中的系统调用工具(二十五):跟踪系统
原文出处:
原作者:Amit Kumar Sahaand Sayantini Ghosh
翻译时间:2008 年 3 月 3 日
译者:王旭
译者注:翻译文章文章来改变你的心情,strace是一个有用的工具,LinuxGazette是一本不错的杂志,希望你喜欢这篇文章。
了解一切如何运作很有趣。所有 C 程序员都知道在他们的 C 程序的“输入-处理-输出”循环中使用了许多系统调用。看到程序中使用了哪些系统调用,无疑是非常令人兴奋的。这篇文章就是关于这个话题的,让我们开始吧。
什么是“strace”?
'strace' 是一个用于跟踪进程在运行时进行的系统调用的工具。它还报告进程收到的信号(或软中断)。
根据手册页,在最简单的情况下,“strace 运行指定的命令,直到命令完成。它拦截并记录进程收到的系统调用和信号。”
直接在终端中输入“strace”命令来查看它的各种开关和选项:
$ strace
usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]
[-p pid] ... [-s strsize] [-u username] [-E var=val] ...
[command [arg ...]]
or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...
[command [arg ...]]
-c -- count time, calls, and errors for each syscall and report summary
[[[etc.]]]
跟踪系统调用
从一个简单的例子开始。考虑以下 C 代码(列表1):
/* Listing 1*/
#include
int main()
{
return 0;
}
假设编译后的目标文件名为‘temp.o’。运行如下:
$strace ./temp.o
您将获得以下跟踪结果输出:
execve("./temp.o", ["./temp.o"], [/* 36 vars */]) = 0
brk(0) = 0x804a000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fba000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=68539, ...}) = 0
mmap2(NULL, 68539, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fa9000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "177ELF111331`100"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=1307104, ...}) = 0
mmap2(NULL, 1312164, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e68000
mmap2(0xb7fa3000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13b) = 0xb7fa3000
mmap2(0xb7fa6000, 9636, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7fa6000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e67000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e676c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7fa3000, 4096, PROT_READ) = 0
munmap(0xb7fa9000, 68539) = 0
exit_group(0) = ?
Process 8909 detached
现在,让我们将理论与实践相结合。
我们知道,当用户输入命令或可执行文件运行时,系统会创建一个“子”Shell,并使用这个子Shell来运行程序。这是通过系统调用“execve”实现的。因此,跟踪结果从以下内容开始:
execve("./temp.o", ["./temp.o"], [/* 36 vars */]) = 0
接下来,进程调用'brk()','open','access','open','close',直到最终进程从shell分离并使用“exit_group(0)”启动。
如上,跟踪过程显示了系统调用及其返回值。
strace 的信号报告功能
我们来看看“strace”的信号上报功能。考虑以下 C 代码(列表2):
/*Listing 2*/
#include
int main()
{
int i;
for(i=0;i>=0;i++)
printf("infinityn");
return 0;
}
假设编译输出的可执行文件是“temp-1.o”。运行如下:
$ strace -o trace.txt ./temp-1.o
这里,“-o”开关会将跟踪结果保存到“trace.txt”文件中。
在这里,您将看到“write()”系统调用将被连续调用。现在,使用“ctrl-c”结束进程
现在,查看“trace.txt”
$cat trace.txt
最后几行应该是:
--- SIGINT (Interrupt) @ 0 (0) ---
+++ killed by SIGINT +++
因为我们使用"ctrl-c"结束进程,所以发送信号SIGINT给进程,就像"strace"的输出一样。
采集与系统调用相关的统计数据
使用“strace”,您还可以对跟踪的系统调用进行一些简单的统计。这是通过“-c”开关实现的。例如:
$ strace -o trace-1.txt -c ./temp-1.o # 运行上述可执行程序 'temp-1.o'
$ cat trace-1.txt
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.007518 0 46702 write
0.00 0.000000 0 1 read
0.00 0.000000 0 2 open
0.00 0.000000 0 2 close
0.00 0.000000 0 1 execve
0.00 0.000000 0 3 3 access
0.00 0.000000 0 1 brk
0.00 0.000000 0 1 munmap
0.00 0.000000 0 1 mprotect
0.00 0.000000 0 7 mmap2
0.00 0.000000 0 3 fstat64
0.00 0.000000 0 1 set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00 0.007518 46725 3 total
如上,除了其他输出信息外,还输出了系统调用的统计信息,“write()”系统调用(总共运行了46702次),占用了进程的大部分时间 (100%)。
后记
本文简单介绍了“strace”的一些基本功能。该工具在搜索可执行程序中的错误和查找崩溃点时非常有用。使用“strace”可以大大减少可能出现问题的范围。
与‘GNU Debugger’ (gdb) 和‘ltrace’一起,“strace”为 Linux 程序员提供了强大的调试功能。
有用的链接: