微信搜索superit|邀请体验:大数据, 数据管理、OLAP分析与可视化平台 | 赞助作者:赞助作者

神器之strace

shell aide_941 23℃

神器之strace

liamu 

2018.05.14 17:44* 字数 809 阅读 1320评论 0

什么是strace

strace是Linux环境下的一款程序调试工具,用来监察一个应用程序所使用的系统调用。
Strace是一个简单的跟踪系统调用执行的工具。在其最简单的形式中,它可以从开始到结束跟踪二进制的执行,并在进程的生命周期中输出一行具有系统调用名称,每个系统调用的参数和返回值的文本行。

在Linux中,进程是不能直接去访问硬件设备的,比如读取磁盘文件、接收网络数据等,但可以将用户态模式切换到内核模式,通过系统调用来访问硬件设备。这时strace就可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间、调用次数,成功和失败的次数。

strace能做什么

  • 它可以基于特定的系统调用或系统调用组进行过滤
  • 它可以通过统计特定系统调用的使用次数,所花费的时间,以及成功和错误的数量来分析系统调用的使用。
  • 它跟踪发送到进程的信号。
  • 可以通过pid附加到任何正在运行的进程。
  • 调试性能问题,查看系统调用的频率,找出耗时的程序段
  • 查看程序读取的是哪些文件从而定位比如配置文件加载错误问题
  • 查看某个php脚本长时间运行“假死”情况
  • 当程序出现“Out of memory”时被系统发出的SIGKILL信息所kill
    另外因为strace拿到的是系统调用相关信息,一般也即是IO操作信息,这个对于排查比如cpu占用100%问题是无能为力的。这个时候就可以使用GDB工具了。

phptrace
因为strace只能追踪到系统调用信息,而拿不到php代码层的调用信息。phptrace扩展就是为了解决这个问题,phptrace包含两个功能:1. 打印当前PHP调用栈,2. 实时追踪PHP调用。这样就能更方便我们去查看到我们需要的信息。phptrace wiki

strace的使用

1、找出程序在启动时读取的配置文件

[root@localhost ~]# strace php 2>&1 | grep php.ini
open("/Data/apps/php7/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/Data/apps/php7/etc/php.ini", O_RDONLY) = 3

2、使用strace来跟踪cat查看一个文件做了什么

[root@localhost mau]# strace cat index.php
execve("/usr/bin/cat", ["cat", "index.php"], [/* 27 vars */]) = 0
brk(0)                                  = 0x60d000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7ff9000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106900, ...}) = 0
mmap(NULL, 106900, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ffff7fde000
close(3)                                = 0
open("/usr/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2107768, ...}) = 0
mmap(NULL, 3932736, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ffff7a1b000
mprotect(0x7ffff7bd1000, 2097152, PROT_NONE) = 0
mmap(0x7ffff7dd1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7ffff7dd1000
mmap(0x7ffff7dd7000, 16960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffff7dd7000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7fdd000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7fdb000
arch_prctl(ARCH_SET_FS, 0x7ffff7fdb740) = 0
mprotect(0x7ffff7dd1000, 16384, PROT_READ) = 0
mprotect(0x60b000, 4096, PROT_READ)     = 0
mprotect(0x7ffff7ffc000, 4096, PROT_READ) = 0
munmap(0x7ffff7fde000, 106900)          = 0
brk(0)                                  = 0x60d000
brk(0x62e000)                           = 0x62e000
brk(0)                                  = 0x62e000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106065056, ...}) = 0
mmap(NULL, 106065056, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ffff14f4000
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
open("index.php", O_RDONLY)             = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=17, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "<?php\nphpinfo();\n", 65536)   = 17
write(1, "<?php\nphpinfo();\n", 17<?php
phpinfo();
)     = 17
read(3, "", 65536)                      = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

跟踪read函数

[root@localhost mau]# strace -e read cat index.php
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\34\2\0\0\0\0\0"..., 832) = 832
read(3, "<?php\nphpinfo();\n", 65536)   = 17
<?php
phpinfo();
read(3, "", 65536)                      = 0
+++ exited with 0 +++

统计每一系统调用的所执行的时间,次数和出错的次数

[root@localhost mau]# strace -c cat index.php
<?php
phpinfo();
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 22.22    0.000016           2         8           mmap
 15.28    0.000011           3         4           open
 12.50    0.000009           2         4           mprotect
  9.72    0.000007           7         1           write
  9.72    0.000007           1         6           close
  6.94    0.000005           1         5           fstat
  6.94    0.000005           5         1           munmap
  5.56    0.000004           1         3           read
  4.17    0.000003           1         4           brk
  2.78    0.000002           2         1         1 access
  2.78    0.000002           2         1           fadvise64
  1.39    0.000001           1         1           execve
  0.00    0.000000           0         1           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.000072                    40         1 total

显示每一调用所耗的时间

[root@localhost mau]# strace -T cat index.php 2>&1|grep read
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\34\2\0\0\0\0\0"..., 832) = 832 <0.000007>
read(3, "<?php\nphpinfo();\n", 65536)   = 17 <0.000009>
read(3, "", 65536)                      = 0 <0.000007>

3、为什么这个程序不能打开我的文件?

当我们开发了一个PHP扩展,可以PHP为什么加载不到我们的扩展文件,通过命令:

[root@localhost mau]# strace -e open php 2>&1 | grep phpfuns

在输出的结果中查找失败的open()或access()系统调用,很有可能是因为权限问题导致的。

4、查看程序在干什么

[root@localhost system]# strace -p $pid
Process 3625 attached
futex(0x13517c4, FUTEX_WAIT_PRIVATE, 527904, NULL) = -1 EAGAIN (Resource temporarily unavailable)
futex(0x13517c4, FUTEX_WAIT_PRIVATE, 527912, NULL) = 0
futex(0x134e7e0, FUTEX_WAKE_PRIVATE, 1) = 0
setsockopt(39, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
sendto(39, "J\0\0\0\n5.6.30\0\35\7\4\0j;'O<{xh\0\377\367\10\2\0\177\200"..., 78, MSG_DONTWAIT, NULL, 0) = 78
recvfrom(39, "\263\0\0\1", 4, MSG_DONTWAIT, NULL, NULL) = 4
recvfrom(39, "\215\242?\0\0\0\0@\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 179, MSG_DONTWAIT, NULL, NULL) = 179
access("./db_firewall_log", F_OK)       = 0
open("./db_firewall_log/db.opt", O_RDONLY) = -1 ENOENT (No such file or directory)
sendto(39, "\7\0\0\2\0\0\0\2\0\0\0", 11, MSG_DONTWAIT, NULL, 0) = 11
recvfrom(39, "\17\0\0\0", 4, MSG_DONTWAIT, NULL, NULL) = 4
recvfrom(39, "\3SET NAMES utf8", 15, MSG_DONTWAIT, NULL, NULL) = 15
sendto(39, "\7\0\0\1\0\0\0\2\0\0\0", 11, MSG_DONTWAIT, NULL, 0) = 11
recvfrom(39, "\21\0\0\0", 4, MSG_DONTWAIT, NULL, NULL) = 4
recvfrom(39, "\3set autocommit=0", 17, MSG_DONTWAIT, NULL, NULL) = 17

5、为什么****不能连接到该服务器?

[root@localhost mau]# strace -e poll,select,connect,recvfrom,sendto ssh root@172.16.1.137
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
poll([{fd=3, events=POLLIN}], 1, 10)    = 1 ([{fd=3, revents=POLLIN}])
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
sendto(3, "\24\0\0\0\26\0\1\3\3537\365Z\0\0\0\0\0\0\0\0", 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20
connect(4, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("172.16.1.137")}, 16) = -1 ETIMEDOUT (Connection timed out)
ssh: connect to host 172.16.1.137 port 22: Connection timed out
+++ exited with 255 +++

strace调试php

[root@localhost mau]# strace -ff -o strace.log -f -F -T /Data/apps/php7/sbin/php-fpm -c /Data/apps/php7/etc/php-fpm.conf
[root@localhost mau]# ls
index.php0

转载请注明:SuperIT » 神器之strace

喜欢 (0)or分享 (0)