命令介绍
strace是Linux环境下的一款程序调试工具,用来输出一个应用程序所使用的系统调用。
strace底层使用内核的ptrace特性来实现其功能。
什么是系统调用?
系统调用是通向操作系统本身的接口,是面向底层硬件的。通过系统调用,可以使得用户态运行的进程与硬件设备(如CPU、磁盘、打印机等)进行交互,是操作系统留给应用程序的一个接口。
常用选项
-t 在每行输出的前面显示时间(精确到秒)
-tt 在每行输出的前面显示时间(精确到毫秒)
-T 显示每次系统调用所花费的时间
-v 对于某些相关调用,显示详细信息(把完整的环境变量,文件stat结构等打出来)
-f 跟踪目标进程,以及目标进程创建的所有子进程
-e 指定要跟踪的系统调用
-o 把strace的输出写到文件中
-s 当系统调用的某个参数是字符串时,最多输出指定长度的内容,默认是32个字节
-p 指定要跟踪的进程pid, 要同时跟踪多个pid, 重复多次-p选项即可。
-c 统计每种系统调用所执行的时间,调用次数,出错次数。
使用
1.追踪打开文件的系统调用
1[root@localhost ~]# strace cat /etc/hosts 2 3execve("/usr/bin/cat", ["cat", "/etc/hosts"], 0x7fff79f5beb8 /* 26 vars */) = 0 4brk(NULL) = 0x81e000 5mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3cee950000 6access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) 7open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 8fstat(3, {st_mode=S_IFREG|0644, st_size=20640, ...}) = 0 9mmap(NULL, 20640, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3cee94a000 10close(3) = 0 11open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 12read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`&\2\0\0\0\0\0"..., 832) = 832 13fstat(3, {st_mode=S_IFREG|0755, st_size=2156240, ...}) = 0 14mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f3cee362000 15mprotect(0x7f3cee525000, 2097152, PROT_NONE) = 0 16mmap(0x7f3cee725000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7f3cee725000 17mmap(0x7f3cee72b000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f3cee72b000 18close(3) = 0 19mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3cee949000 20mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3cee947000 21arch_prctl(ARCH_SET_FS, 0x7f3cee947740) = 0 22mprotect(0x7f3cee725000, 16384, PROT_READ) = 0 23mprotect(0x60b000, 4096, PROT_READ) = 0 24mprotect(0x7f3cee951000, 4096, PROT_READ) = 0 25munmap(0x7f3cee94a000, 20640) = 0 26brk(NULL) = 0x81e000 27brk(0x83f000) = 0x83f000 28brk(NULL) = 0x83f000 29open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 30fstat(3, {st_mode=S_IFREG|0644, st_size=106176928, ...}) = 0 31mmap(NULL, 106176928, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3ce7e1f000 32close(3) = 0 33fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 34open("/etc/hosts", O_RDONLY) = 3 35fstat(3, {st_mode=S_IFREG|0644, st_size=158, ...}) = 0 36fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0 37read(3, "127.0.0.1 localhost localhost."..., 65536) = 158 38write(1, "127.0.0.1 localhost localhost."..., 158127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 39::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 40) = 158 41read(3, "", 65536) = 0 42close(3) = 0 43close(1) = 0 44close(2) = 0 45exit_group(0) = ? 46+++ exited with 0 +++
2.显示系统调用的时间
1[root@localhost ~]# strace -tt -T cat /etc/hosts 2 311:25:50.561449 open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 <0.000023> 411:25:50.561522 fstat(3, {st_mode=S_IFREG|0644, st_size=106176928, ...}) = 0 <0.000013> 511:25:50.561585 mmap(NULL, 106176928, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7ecb038000 <0.000018> 611:25:50.561649 close(3) = 0 <0.000013> 711:25:50.561830 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 <0.000017> 811:25:50.561908 open("/etc/hosts", O_RDONLY) = 3 <0.000024> 911:25:50.561979 fstat(3, {st_mode=S_IFREG|0644, st_size=158, ...}) = 0 <0.000014> 1011:25:50.562046 fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0 <0.000014> 1111:25:50.562118 read(3, "127.0.0.1 localhost localhost."..., 65536) = 158 <0.000019> 1211:25:50.562183 write(1, "127.0.0.1 localhost localhost."..., 158127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 13::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 14) = 158 <0.000018> 1511:25:50.562244 read(3, "", 65536) = 0 <0.000014> 1611:25:50.562304 close(3) = 0 <0.000016> 1711:25:50.562386 close(1) = 0 <0.000013> 1811:25:50.562443 close(2) = 0 <0.000012> 19# 时间戳 # 花费的时间
3.跟踪特定系统调用
-e trace=file 文件相关的调用(参数中有文件名)
-e trace=process 进程管理相关的调用,比如fork/exec/exit_group
-e trace=network 网络通信相关的调用,比如socket/sendto/connect
-e trace=signal 信号相关的调用,比如kill/sigaction
-e trace=desc 和文件描述符相关,比如write/read/select/epoll等
-e trace=ipc 进程通信相关的调用,比如shmget等
1# 跟踪文件访问相关系统调用 2[root@localhost ~]# strace -e file cat /etc/hosts 3execve("/usr/bin/cat", ["cat", "/etc/hosts"], 0x7fff79c90c58 /* 26 vars */) = 0 4access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) 5open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 6open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 7open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 8open("/etc/hosts", O_RDONLY) = 3
4.跟踪多线程(进程)应用的系统调用
下面是一个多线程demo代码。
1#include <stdio.h> 2#include <unistd.h> 3#include <pthread.h> 4 5void* ThreadA(void* par) 6{ 7 while(1) 8 { 9 printf("hello world\n"); 10 sleep(1); 11 } 12} 13 14int main() 15{ 16 pthread_t t1; 17 pthread_create(&t1, NULL, ThreadA, NULL); 18 pthread_join(t1, NULL); 19 20 return 0; 21}
编译代码
# gcc demo.c -o demo -lpthread
开始跟踪
# strace -ff -o out ./demo
执行完成后得到两个文件(每个线程一个)
1# ls out.* 2out.7611 out.7612
主线程 out.7611
1mprotect(0x7fa0e4b6e000, 16384, PROT_READ) = 0 2mprotect(0x7fa0e4d8f000, 4096, PROT_READ) = 0 3mprotect(0x600000, 4096, PROT_READ) = 0 4mprotect(0x7fa0e4fb6000, 4096, PROT_READ) = 0 5munmap(0x7fa0e4faf000, 20776) = 0 6set_tid_address(0x7fa0e4faca10) = 7611 7set_robust_list(0x7fa0e4faca20, 24) = 0 8rt_sigaction(SIGRTMIN, {sa_handler=0x7fa0e4b7f860, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7fa0e4b88630}, NULL, 8) = 0 9rt_sigaction(SIGRT_1, {sa_handler=0x7fa0e4b7f8f0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7fa0e4b88630}, NULL, 8) = 0 10rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 11getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 12mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7fa0e3faa000 13brk(NULL) = 0x15c8000 14brk(0x15e9000) = 0x15e9000 15brk(NULL) = 0x15e9000 16mprotect(0x7fa0e3faa000, 4096, PROT_NONE) = 0 17clone(child_stack=0x7fa0e47a9fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fa0e47aa9d0, tls=0x7fa0e47aa700, child_tidptr=0x7fa0e47aa9d0) = 7612 18futex(0x7fa0e47aa9d0, FUTEX_WAIT, 7612, NULL) = 0 19exit_group(0) = ? 20+++ exited with 0 +++
工作线程 out.7612
1set_robust_list(0x7fa0e47aa9e0, 24) = 0 2fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 3mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa0e4fb4000 4write(1, "hello world\n", 12) = 12 5madvise(0x7fa0e3faa000, 8368128, MADV_DONTNEED) = 0 6exit(0) = ? 7+++ exited with 0 +++