strace- system calls and signals trace.跟踪系统中调用和信号信息。
最简单的情况下,strace ls 会执行ls命令直到结束,监听记录ls进程执行过程中的系统调用信息和进程接收的信号,每个系统调用的名字、参数和返回值都打印到标准输出,也可以使用-o选项输出到文件。strace是很有用的调试工具,对于源码不可见的程序,非常有用,因为系统调用和信号是用户态和内核态之间交互的接口,strace将有助于程序员定位bug,
如下,为在博主电脑上运行
$strace ls
的输出信息:
execve("/bin/ls", ["ls"], [/* 65 vars */]) = 0
brk(0) = 0x805f000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7792000
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=123690, ...}) = 0
mmap2(NULL, 123690, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7773000
close(3) = 0
open("/lib/librt.so.1", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`\31\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=30552, ...}) = 0
mmap2(NULL, 33392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb776a000
mmap2(0xb7771000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6) = 0xb7771000
close(3) = 0
open("/lib/libacl.so.1", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@\32\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=26144, ...}) = 0
mmap2(NULL, 29028, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7762000
mmap2(0xb7768000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x5) = 0xb7768000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20m\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1323292, ...}) = 0
mmap2(NULL, 1329448, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb761d000
mmap2(0xb775c000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13f) = 0xb775c000
mmap2(0xb775f000, 10536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb775f000
close(3) = 0
open("/lib/libpthread.so.0", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360I\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=121931, ...}) = 0
mmap2(NULL, 98796, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7604000
mmap2(0xb7619000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14) = 0xb7619000
mmap2(0xb761b000, 4588, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb761b000
close(3) = 0
open("/lib/libattr.so.1", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\20\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=17788, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7603000
mmap2(NULL, 20656, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75fd000
mmap2(0xb7601000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3) = 0xb7601000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75fc000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75fc6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7601000, 4096, PROT_READ) = 0
mprotect(0xb7619000, 4096, PROT_READ) = 0
mprotect(0xb775c000, 8192, PROT_READ) = 0
mprotect(0xb7768000, 4096, PROT_READ) = 0
mprotect(0xb7771000, 4096, PROT_READ) = 0
mprotect(0x805d000, 4096, PROT_READ) = 0
mprotect(0xb77b0000, 4096, PROT_READ) = 0
munmap(0xb7773000, 123690) = 0
set_tid_address(0xb75fc728) = 19879
set_robust_list(0xb75fc730, 0xc) = 0
futex(0xbf999d90, FUTEX_WAKE_PRIVATE, 1) = 0
futex(0xbf999d90, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, bf999da0) = -1 EAGAIN (Resource temporarily unavailable)
rt_sigaction(SIGRTMIN, {0xb76083d0, [], SA_SIGINFO}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {0xb76088c0, [], SA_RESTART|SA_SIGINFO}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
uname({sys="Linux", node="erlv-laptop", ...}) = 0
brk(0) = 0x805f000
brk(0x8080000) = 0x8080000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=5129504, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb73fc000
mmap2(NULL, 1638400, PROT_READ, MAP_PRIVATE, 3, 0x2b6) = 0xb726c000
close(3) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=48, ws_col=154, ws_xpixel=0, ws_ypixel=0}) = 0
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
fcntl64(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
getdents64(3, /* 11 entries */, 32768) = 328
getdents64(3, /* 0 entries */, 32768) = 0
close(3) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7791000
write(1, "Segmentation WOPT-I.html WOPT-"..., 101Segmentation WOPT-I.html WOPT-I.html~ donkey.png gcc gcc~ lingccne_wrd1.sql.gz plugins themes
) = 101
close(1) = 0
munmap(0xb7791000, 4096) = 0
close(2) = 0
exit_group(0) = ?
对于每个系统调用,都给出了参数和返回值,如:
execve("/bin/ls", ["ls"], [/* 65 vars */]) = 0
每个错误都给出了错误编号和出错提示信息:
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
从上面还可以看到,每个输出都清楚的打印了每个信号以及参数的符号,所以strace可读性很强。
fstat64(3, {st_mode=S_IFREG|0644, st_size=5129504, ...}) = 0
从上面这行可以看出,对于结构体指针,都做了解析,所有成员都使用符号打印出来。
下面介绍几个strace中的选项:
-c 记录系统调用和每个系统调用中错误的类型和时间并在程序退出时打印汇总信息。
-f 像跟踪当前进程一样跟踪该进程创建的子进程。
-t/tt/ttt/T 输出信息时,加上不同的时间标签。
-e trace= 通过各种形式指定跟踪类型,有以下集中set,file,process,network,signal,ipc,desc

strace通过信号操作被跟踪的进程,以获知其call的系统调用,具体机制应该也很有意思
@donghao, 其实这篇文章是因为看到你写的内核flush分析时提到了strace,才班门弄斧了一下:)
看来strace用了很多信号通信,这个我就不太懂了呵呵,有机会研究一下。
Pingback: 《编译点滴》半年记 « 编译点滴
strace是通过ptrace syscall来实现其功能的。
又学到了新东西,谢谢:)
Strace用来调bug还是很强大的
二进制翻译时,很多系统调用方面的问题,都要靠strace来看吧。