1.功能介绍:
在理想世界里,每当一个程序不能正常执行一个功能时,它就会给出一个有用的错误提示,告诉你在足够的改正错误的线索。但遗憾的是,我们不是生活在理想世界 里,起码不总是生活在理想世界里。有时候一个程序出现了问题,你无法找到原因,这就是调试程序出现的原因。strace是一个必不可少的调试工具,strace用来监视系统调用。你不仅可以调试一个新开始的程序,也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上 面),而 ltrace(library call tracer)是一个执行指定的命令直到该命令结束,他会拦截和记录动态链接库的函数,和该进程接受到的信号,他也可以拦截该程序调用的系统函数。
2.常用参数:
-f :除了跟踪当前进程外,还跟踪其子进程。
-F :尝试跟踪vfork调用
-o :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。
-p :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。
-T :记录各个系统调用花费的时间,精确到微秒
-r :以第一个系统调用(通常为execve)计时,精确到微秒
-e expr : 只会记录指定的调用函数
3.命令举例:
strace -f -o vim.strace vim: 跟踪vim及其子进程的运行,将输出信息写到文件vim.strace。
ltrace -p 234: 跟踪一个pid为234的已经在运行的进程。
strace -o output.txt -T -tt -e trace=all -p 28979
上面的含义是 跟踪28979进程的所有系统调用(-e trace=all),并统计系统调用的花费时间,以及开始时间(并以可视化的时分秒格式显示),最后将记录结果存在output.txt文件里面。
4.示例代码与分析:
int main(int argc, char** argv)
{
getpid(); //该系统调用起到标识作用
if(argc < 2)
{
printf("hang (user|system)\n");
return 1;
}
if(!strcmp(argv[1], "user"))
while(1);
else if(!strcmp(argv[1], "system"))
sleep(500);
return 0;
}
a.用户态挂死跟踪输出:
lx@LX:~$ gcc hang.c -o hang
lx@LX:~$ strace ./hang user
……
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xb59000, 4096, PROT_READ) = 0
munmap(0xb77bf000, 80682) = 0
getpid() = 14539
b.内核态挂死跟踪输出:
lx@LX:~$ strace ./hang system
……
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xddf000, 4096, PROT_READ) = 0
munmap(0xb7855000, 80682) = 0
getpid() = 14543
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({500, 0},
c. 输出结果分析:
用户态挂死情况下,strace在getpid()一行输出之后没有其他系统调用输出;进程在内核态挂死,最后一行的系统调用nanosleep不能完整显示,这里nanosleep没有返回值表示该调用尚未完成,
因而我们可以得出以下结论:使用strace跟踪挂死程序,如果最后一行系统调用显示完整,程序在逻辑代码处挂死;如果最后一行系统调用显示不完整,程序在该系统调用处挂死。
下面是ltrace 与strace 跟踪我们nginx的情况:
ltrace -r -p 26555(nginx worker 对应的进程号)
0.000205 epoll_wait(21, 0xf6e550, 512, 500, 0x7fff34eeaa93) = 0
0.500967 gettimeofday(0x7fff34eeac70, NULL) = 0
0.000318 epoll_wait(21, 0xf6e550, 512, 500, 0x7fff34eeaa93) = 0
0.500945 gettimeofday(0x7fff34eeac70, NULL) = 0
0.000243 memcpy(0x6f4fe7, "26", 2) = 0x6f4fe7
0.000204 memcpy(0x6f4fee, "2014", 4) = 0x6f4fee
0.000255 memcpy(0x6f4ff4, "7", 1) = 0x6f4ff4
0.000327 memcpy(0x6f4ff6, "43", 2) = 0x6f4ff6
0.000205 memcpy(0x6f4ff9, "11", 2) = 0x6f4ff9
0.000200 localtime_r(0x7fff34eeaba8, 0x7fff34eeac30, 0x4bc00a, 12593, 0x7fff34eeaa92)
分析: 0.000205 调用系统所话的时间,单位为微秒,epoll_wait()系统函数,我们可以通过时间来简单的判断一下,运行函数是否异常
strace -r -p 26555(nginx worker 对应的进程号)
0.000029 recvfrom(46, "POST /rewardapi/v2/applyCancelCo"..., 4096, 0, NULL, NULL) = 453
0.000105 sendto(9, "*5\r\n$5\r\nHMGET\r\n$21\r\n1111111111:a"..., 88, 0, NULL, 0) = 88
0.000045 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000026 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000430 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000057 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000426 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000062 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.001000 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000028 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000468 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000031 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000893 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000028 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.001047 recvfrom(9, "*3\r\n$40\r\nBB9318B102E320C09B8AB9D"..., 8192, 0, NULL, NULL) = 61
0.000114 close(37) = 0
0.000025 munmap(0x7fe59c1ba000, 4096) = 0
在理想世界里,每当一个程序不能正常执行一个功能时,它就会给出一个有用的错误提示,告诉你在足够的改正错误的线索。但遗憾的是,我们不是生活在理想世界 里,起码不总是生活在理想世界里。有时候一个程序出现了问题,你无法找到原因,这就是调试程序出现的原因。strace是一个必不可少的调试工具,strace用来监视系统调用。你不仅可以调试一个新开始的程序,也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上 面),而 ltrace(library call tracer)是一个执行指定的命令直到该命令结束,他会拦截和记录动态链接库的函数,和该进程接受到的信号,他也可以拦截该程序调用的系统函数。
2.常用参数:
-f :除了跟踪当前进程外,还跟踪其子进程。
-F :尝试跟踪vfork调用
-o :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。
-p :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。
-T :记录各个系统调用花费的时间,精确到微秒
-r :以第一个系统调用(通常为execve)计时,精确到微秒
-e expr : 只会记录指定的调用函数
3.命令举例:
strace -f -o vim.strace vim: 跟踪vim及其子进程的运行,将输出信息写到文件vim.strace。
ltrace -p 234: 跟踪一个pid为234的已经在运行的进程。
strace -o output.txt -T -tt -e trace=all -p 28979
上面的含义是 跟踪28979进程的所有系统调用(-e trace=all),并统计系统调用的花费时间,以及开始时间(并以可视化的时分秒格式显示),最后将记录结果存在output.txt文件里面。
4.示例代码与分析:
int main(int argc, char** argv)
{
getpid(); //该系统调用起到标识作用
if(argc < 2)
{
printf("hang (user|system)\n");
return 1;
}
if(!strcmp(argv[1], "user"))
while(1);
else if(!strcmp(argv[1], "system"))
sleep(500);
return 0;
}
a.用户态挂死跟踪输出:
lx@LX:~$ gcc hang.c -o hang
lx@LX:~$ strace ./hang user
……
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xb59000, 4096, PROT_READ) = 0
munmap(0xb77bf000, 80682) = 0
getpid() = 14539
b.内核态挂死跟踪输出:
lx@LX:~$ strace ./hang system
……
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xddf000, 4096, PROT_READ) = 0
munmap(0xb7855000, 80682) = 0
getpid() = 14543
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({500, 0},
c. 输出结果分析:
用户态挂死情况下,strace在getpid()一行输出之后没有其他系统调用输出;进程在内核态挂死,最后一行的系统调用nanosleep不能完整显示,这里nanosleep没有返回值表示该调用尚未完成,
因而我们可以得出以下结论:使用strace跟踪挂死程序,如果最后一行系统调用显示完整,程序在逻辑代码处挂死;如果最后一行系统调用显示不完整,程序在该系统调用处挂死。
下面是ltrace 与strace 跟踪我们nginx的情况:
ltrace -r -p 26555(nginx worker 对应的进程号)
0.000205 epoll_wait(21, 0xf6e550, 512, 500, 0x7fff34eeaa93) = 0
0.500967 gettimeofday(0x7fff34eeac70, NULL) = 0
0.000318 epoll_wait(21, 0xf6e550, 512, 500, 0x7fff34eeaa93) = 0
0.500945 gettimeofday(0x7fff34eeac70, NULL) = 0
0.000243 memcpy(0x6f4fe7, "26", 2) = 0x6f4fe7
0.000204 memcpy(0x6f4fee, "2014", 4) = 0x6f4fee
0.000255 memcpy(0x6f4ff4, "7", 1) = 0x6f4ff4
0.000327 memcpy(0x6f4ff6, "43", 2) = 0x6f4ff6
0.000205 memcpy(0x6f4ff9, "11", 2) = 0x6f4ff9
0.000200 localtime_r(0x7fff34eeaba8, 0x7fff34eeac30, 0x4bc00a, 12593, 0x7fff34eeaa92)
分析: 0.000205 调用系统所话的时间,单位为微秒,epoll_wait()系统函数,我们可以通过时间来简单的判断一下,运行函数是否异常
strace -r -p 26555(nginx worker 对应的进程号)
0.000029 recvfrom(46, "POST /rewardapi/v2/applyCancelCo"..., 4096, 0, NULL, NULL) = 453
0.000105 sendto(9, "*5\r\n$5\r\nHMGET\r\n$21\r\n1111111111:a"..., 88, 0, NULL, 0) = 88
0.000045 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000026 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000430 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000057 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000426 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000062 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.001000 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000028 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000468 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000031 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.000893 recvfrom(9, 0x408362d0, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
0.000028 poll([{fd=9, events=POLLIN}], 1, -1) = 1 ([{fd=9, revents=POLLIN}])
0.001047 recvfrom(9, "*3\r\n$40\r\nBB9318B102E320C09B8AB9D"..., 8192, 0, NULL, NULL) = 61
0.000114 close(37) = 0
0.000025 munmap(0x7fe59c1ba000, 4096) = 0